Merge remote-tracking branch 'linux-2.6.32.y/master' into develop
[firefly-linux-kernel-4.4.55.git] / drivers / misc / mtk23d.c
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/i2c.h>
4 #include <linux/irq.h>
5 #include <linux/gpio.h>
6 #include <linux/input.h>
7 #include <linux/platform_device.h>
8 #include <linux/fs.h>
9 #include <linux/uaccess.h>
10 #include <linux/miscdevice.h>
11 #include <linux/circ_buf.h>
12 #include <linux/interrupt.h>
13 #include <linux/miscdevice.h>
14 #include <mach/iomux.h>
15 #include <mach/gpio.h>
16 //#include <mach/spi_fpga.h>
17 #include <linux/delay.h>
18 #include <linux/poll.h>
19 #include <linux/wait.h>
20 //#include <linux/android_power.h>
21 //#include <asm/arch/gpio_extend.h>
22 #include <linux/workqueue.h>
23 #include <linux/mtk23d.h>
24 #include <linux/wakelock.h>
25 #include "../mtd/rknand/api_flash.h"
26
27 MODULE_LICENSE("GPL");
28
29 #define DEBUG
30 #ifdef DEBUG
31 #define MODEMDBG(x...) printk(x)
32 #else
33 #define MODEMDBG(fmt,argss...)
34 #endif
35
36 #define MTK23D_RESET 0x01
37 #define MTK23D_POWERON  0x02
38 #define MTK23D_POWER_HIGH 0x03
39 #define MTK23D_IMEI_READ  0x04
40 //#define BP_POW_EN     TCA6424_P02
41 //#define BP_STATUS    RK2818_PIN_PH7    //input  high bp sleep
42 //#define AP_STATUS    RK2818_PIN_PA4    //output high ap sleep
43
44 //#define BP_RESET      TCA6424_P11     //Ryan
45
46 //#define AP_BP_WAKEUP  RK2818_PIN_PF5   //output AP wake up BP used rising edge
47 //#define BP_AP_WAKEUP  RK2818_PIN_PE0  //input BP wake up AP
48
49 static bool bpstatus_irq_enable = false;
50 static bool wakelock_inited;
51 static struct wake_lock mtk23d_wakelock;
52
53 #define SLEEP 1
54 #define READY 0
55
56 //struct modem_dev *mt6223d_data = NULL;
57 struct rk2818_23d_data *gpdata = NULL;
58
59 static int  get_bp_statue(struct platform_device *pdev)
60 {
61         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
62         
63         if(gpio_get_value(pdata->bp_statue))
64                 return SLEEP;
65         else
66                 return READY;
67 }
68 static void ap_sleep(struct platform_device *pdev)
69 {
70         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
71         
72         MODEMDBG("ap sleep!\n");
73         gpio_set_value(pdata->ap_statue,GPIO_HIGH);
74 }
75 static void ap_wakeup(struct platform_device *pdev)
76 {
77         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
78         
79         MODEMDBG("ap wakeup!\n");
80         gpio_set_value(pdata->ap_statue,GPIO_LOW);
81 }
82 /* */
83 static void ap_wakeup_bp(struct platform_device *pdev, int wake)//low to wakeup bp
84 {
85         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
86         struct modem_dev *mt6223d_data = platform_get_drvdata(pdev);
87         MODEMDBG("ap_wakeup_bp\n");
88
89         gpio_set_value(pdata->ap_bp_wakeup, wake);  // phc
90         //gpio_set_value(RK2818_PIN_PF5, wake);
91 }
92
93 static void bpwakeup_work_func_work(struct work_struct *work)
94 {
95         struct modem_dev *bdata = container_of(work, struct modem_dev, work);
96         
97         MODEMDBG("%s\n", __FUNCTION__);
98         
99 }
100 /*  */
101 static irqreturn_t  bpwakeup_work_func(int irq, void *data)
102 {
103         struct modem_dev *mt6223d_data = (struct modem_dev *)data;
104         
105         MODEMDBG("bpwakeup_work_func\n");
106         schedule_work(&mt6223d_data->work);
107         return IRQ_HANDLED;
108 }
109 static irqreturn_t  bp_apwakeup_work_func(int irq, void *data)
110 {
111         //struct modem_dev *dev = &mtk23d_misc;
112         
113         MODEMDBG("bp_apwakeup_work_func\n");
114         //wake_up_interruptible(&dev->wakeup);
115         return IRQ_HANDLED;
116 }
117
118 static irqreturn_t BBwakeup_isr(int irq, void *dev_id)
119 {
120         struct rk2818_23d_data *pdata = dev_id;
121         
122         MODEMDBG("%s \n", __FUNCTION__);
123         //if(irq != gpio_to_irq(RK29_PIN1_PC0))
124         //{
125         //              printk("irq != gpio_to_irq(RK29_PIN1_PC0) \n");
126         //              return IRQ_NONE;
127         //}
128         
129 //      disable_irq_wake(irq);
130         
131         if(bpstatus_irq_enable == true)
132         {
133                 MODEMDBG("mtk23d_wakelock 3s \n");
134                 wake_lock_timeout(&mtk23d_wakelock, 3 * HZ);
135         }
136                 
137
138         return IRQ_HANDLED;
139 }
140
141 int modem_poweron_off(int on_off)
142 {
143         struct rk2818_23d_data *pdata = gpdata;
144         int result, error = 0, irq = 0; 
145         
146   if(on_off)
147   {
148                         printk("modem_poweron\n");
149                         
150                   gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);  // power on enable
151                   mdelay(300);
152                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_HIGH:GPIO_LOW);  // release reset
153                         msleep(3000);
154                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);  // power on relase
155                                 
156                         #if 1 // phc
157                         rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_UART0_SOUT);
158                         rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_UART0_SIN); 
159                         rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N);
160                         rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_UART0_CTS_N);     
161                         #endif
162                         
163                   gpio_direction_input(pdata->bp_statue);
164                   gpio_direction_input(pdata->bp_ap_wakeup);
165                         
166                         /* ³õʼ»¯BP»½ÐÑAPµÄ¹¦ÄÜ */
167                         wakelock_inited = false;
168                         irq = gpio_to_irq(pdata->bp_statue);
169                         if (irq < 0) {
170                                 printk("can't get pdata->bp_statue irq \n");
171                         }
172                         else
173                         {
174                                 error = request_irq(irq, BBwakeup_isr,
175                                                     IRQF_TRIGGER_FALLING,
176                                                     NULL,
177                                                     pdata);
178                                 if (error) {
179                                         printk("mtk23d_probe bp_statue request_irq error!!! \n");
180                                 }
181                         }
182                         if (!wakelock_inited) {
183                                 wake_lock_init(&mtk23d_wakelock, WAKE_LOCK_SUSPEND, "23d_resume");
184                                 wakelock_inited = true;
185                         }
186   }
187   else
188   {
189                         printk("modem_poweroff\n");
190                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
191                         mdelay(100);
192                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);
193   }
194 }
195 static int power_on =1;
196 static int mtk23d_open(struct inode *inode, struct file *file)
197 {
198         struct rk2818_23d_data *pdata = gpdata;
199         //struct rk2818_23d_data *pdata = gpdata = pdev->dev.platform_data;
200         struct platform_data *pdev = container_of(pdata, struct device, platform_data);
201
202         MODEMDBG("modem_open\n");
203
204         int ret = 0;
205         if(power_on)
206         {
207                 power_on = 0;
208                 modem_poweron_off(1);
209         }
210         device_init_wakeup(&pdev, 1);
211
212         return 0;
213 }
214
215 static int mtk23d_release(struct inode *inode, struct file *file)
216 {
217         MODEMDBG("mtk23d_release\n");
218
219         //gpio_free(pdata->bp_power);
220         return 0;
221 }
222
223 //extern char imei_value[16]; // phc, no find 'imei_value' in rk29 project
224 //char imei_value[16] = {0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5};
225
226 static int mtk23d_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg)
227 {
228         struct rk2818_23d_data *pdata = gpdata;
229         int i;
230         void __user *argp = (void __user *)arg;
231         
232         char SectorBuffer[512];
233         
234         printk("mtk23d_ioctl\n");
235         switch(cmd)
236         {
237                 case MTK23D_RESET:              
238                         printk("MTK23D_RESET\n");
239                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH);
240                         mdelay(100);
241                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
242                         mdelay(300);
243                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_HIGH:GPIO_LOW);
244                         msleep(3000);
245                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);
246                         break;
247                 case MTK23D_IMEI_READ:
248                         printk("MTK23D_IMEI_READ\n");
249                         
250                         GetSNSectorInfo(SectorBuffer); // phc,20110624
251                         
252                         if(copy_to_user(argp, &(SectorBuffer[451]), 16))  // IMEIºó´Ó451Æ«ÒÆ¿ªÊ¼µÄ16bytes£¬µÚÒ»¸öbyteΪ³¤¶È¹Ì¶¨Îª15
253                         {
254                                 printk("ERROR: copy_to_user---%s\n", __FUNCTION__);
255                                 return -EFAULT;
256                         }
257                         //printk("IMEI:%d %d %d %d\n", SectorBuffer[451], SectorBuffer[452], SectorBuffer[453], SectorBuffer[454]);
258                         break;
259                 default:
260                         break;
261         }
262         return 0;
263 }
264
265 static struct file_operations mtk23d_fops = {
266         .owner = THIS_MODULE,
267         .open = mtk23d_open,
268         .release = mtk23d_release,
269         .ioctl = mtk23d_ioctl
270 };
271
272 static struct miscdevice mtk23d_misc = {
273         .minor = MISC_DYNAMIC_MINOR,
274         .name = MODEM_NAME,
275         .fops = &mtk23d_fops
276 };
277
278 static int mtk23d_probe(struct platform_device *pdev)
279 {
280         struct rk2818_23d_data *pdata = gpdata = pdev->dev.platform_data;
281         struct modem_dev *mt6223d_data = NULL;
282         int result, error = 0, irq = 0; 
283         
284         MODEMDBG("mtk23d_probe\n");
285
286         //pdata->io_init();
287
288         mt6223d_data = kzalloc(sizeof(struct modem_dev), GFP_KERNEL);
289         if(NULL == mt6223d_data)
290         {
291                 printk("failed to request mt6223d_data\n");
292                 goto err6;
293         }
294         platform_set_drvdata(pdev, mt6223d_data);
295
296         result = gpio_request(pdata->bp_statue, "mtk23d");
297         if (result) {
298                 printk("failed to request BP_STATUS gpio\n");
299                 goto err5;
300         }
301         
302         result = gpio_request(pdata->ap_statue, "mtk23d");
303         if (result) {
304                 printk("failed to request AP_STATUS gpio\n");
305                 goto err4;
306         }       
307         
308         result = gpio_request(pdata->ap_bp_wakeup, "mtk23d");
309         if (result) {
310                 printk("failed to request AP_BP_WAKEUP gpio\n");
311                 goto err3;
312         }       
313         result = gpio_request(pdata->bp_reset, "mtk23d");
314         if (result) {
315                 printk("failed to request BP_RESET gpio\n");
316                 goto err2;
317         }               
318         result = gpio_request(pdata->bp_power, "mtk23d");
319         if (result) {
320                 printk("failed to request BP_POW_EN gpio\n");
321                 goto err1;
322         }
323         
324         if(pdata->bp_ap_wakeup) // SDK°åÖУ¬¸Ã¿ÚûÓÐÒý³ö
325         {
326                 result = gpio_request(pdata->bp_ap_wakeup, "mtk23d");
327                 if (result) {
328                         printk("failed to request BP_AP_WAKEUP gpio\n");
329                         goto err0;
330                 }               
331         }
332         
333 #if 1 // GPIO³õʼ»¯£¬²¢ÇÒ·Àֹ©µç
334         rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_GPIO1B7);                       
335         gpio_request(RK29_PIN1_PB7, NULL);
336         gpio_direction_output(RK29_PIN1_PB7,GPIO_LOW);
337         gpio_pull_updown(RK29_PIN1_PB7, PullDisable);  // ÏÂÀ­½ûÖ¹
338         
339         rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_GPIO1B6);                
340         gpio_request(RK29_PIN1_PB6, NULL);
341         gpio_direction_output(RK29_PIN1_PB6,GPIO_LOW);  
342         gpio_pull_updown(RK29_PIN1_PB6, PullDisable);  // ÏÂÀ­½ûÖ¹
343         
344         rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_GPIO1C1);                        
345         gpio_request(RK29_PIN1_PC1, NULL);
346         gpio_direction_output(RK29_PIN1_PC1,GPIO_LOW);
347         
348         rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_GPIO1C0);                 
349         gpio_request(RK29_PIN1_PC0, NULL);
350         //gpio_direction_input(RK29_PIN1_PC0);          
351         gpio_direction_output(RK29_PIN1_PC0,GPIO_LOW);
352
353
354   gpio_direction_output(pdata->bp_power, GPIO_LOW);
355         gpio_direction_output(pdata->ap_statue, GPIO_LOW);
356         gpio_direction_output(pdata->ap_bp_wakeup, GPIO_LOW);   
357         gpio_direction_output(pdata->bp_reset, GPIO_LOW);
358         //gpio_direction_output(pdata->bp_statue,GPIO_LOW);
359         gpio_direction_input(pdata->bp_statue);
360         if(pdata->bp_ap_wakeup) // SDK°åÖУ¬¸Ã¿ÚûÓÐÒý³ö
361         {
362                 //gpio_direction_output(pdata->bp_ap_wakeup,GPIO_LOW);
363                 gpio_direction_input(pdata->bp_ap_wakeup);
364         }
365         
366         /*¸´Î»BP*/
367         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH);
368         //mdelay(200);
369         //gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_HIGH:GPIO_LOW);
370 #endif  
371
372         INIT_WORK(&mt6223d_data->work, bpwakeup_work_func_work);
373   power_on = 1;
374         result = misc_register(&mtk23d_misc);
375         if(result)
376         {
377                 MODEMDBG("misc_register err\n");
378         }
379         MODEMDBG("mtk23d_probe ok\n");
380         
381         return result;
382 err0:
383         cancel_work_sync(&mt6223d_data->work);
384         gpio_free(pdata->bp_ap_wakeup);
385 err1:
386         gpio_free(pdata->bp_power);
387 err2:
388         gpio_free(pdata->bp_reset);
389 err3:
390         gpio_free(pdata->ap_bp_wakeup);
391 err4:
392         gpio_free(pdata->ap_statue);
393 err5:
394         gpio_free(pdata->bp_statue);
395 err6:
396         kfree(mt6223d_data);
397 ret:
398         return result;
399 }
400
401 int mtk23d_suspend(struct platform_device *pdev)
402 {
403         int irq, error;
404         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
405         
406         MODEMDBG("%s \n", __FUNCTION__);
407         
408         //enable_irq_wake(irq);
409         ap_sleep(pdev);
410         ap_wakeup_bp(pdev, 0);
411
412         irq = gpio_to_irq(pdata->bp_statue);
413         if (irq < 0) {
414                 printk("can't get pdata->bp_statue irq \n");
415         }
416         else
417         {
418                 printk("enable pdata->bp_statue irq_wake!! \n");
419                 bpstatus_irq_enable = true;
420                 enable_irq_wake(irq);
421         }
422         
423         return 0;
424 }
425
426 int mtk23d_resume(struct platform_device *pdev)
427 {
428         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
429         int irq = 0;
430         
431         MODEMDBG("%s \n", __FUNCTION__);
432         
433         irq = gpio_to_irq(pdata->bp_statue);
434         if(irq)
435         {
436                 printk("disable pdata->bp_statue irq_wake!! \n");
437                 bpstatus_irq_enable = false;
438                 disable_irq_wake(irq);
439         }
440         
441         ap_wakeup(pdev);
442         ap_wakeup_bp(pdev, 1);
443         
444         return 0;
445 }
446
447 void mtk23d_shutdown(struct platform_device *pdev, pm_message_t state)
448 {
449         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
450         struct modem_dev *mt6223d_data = platform_get_drvdata(pdev);
451         
452         MODEMDBG("%s \n", __FUNCTION__);
453
454         modem_poweron_off(0);  // power down
455
456         cancel_work_sync(&mt6223d_data->work);
457         gpio_free(pdata->bp_ap_wakeup);
458         gpio_free(pdata->bp_power);
459         gpio_free(pdata->bp_reset);
460         gpio_free(pdata->ap_bp_wakeup);
461         gpio_free(pdata->ap_statue);
462         gpio_free(pdata->bp_statue);
463         kfree(mt6223d_data);
464 }
465
466 static struct platform_driver mtk23d_driver = {
467         .probe  = mtk23d_probe,
468         .shutdown       = mtk23d_shutdown,
469         .suspend        = mtk23d_suspend,
470         .resume         = mtk23d_resume,
471         .driver = {
472                 .name   = "mtk23d",
473                 .owner  = THIS_MODULE,
474         },
475 };
476
477 static int __init mtk23d_init(void)
478 {
479         MODEMDBG("mtk23d_init ret=%d\n");
480         return platform_driver_register(&mtk23d_driver);
481 }
482
483 static void __exit mtk23d_exit(void)
484 {
485         MODEMDBG("mtk23d_exit\n");
486         platform_driver_unregister(&mtk23d_driver);
487 }
488
489 module_init(mtk23d_init);
490 //late_initcall_sync(mtk23d_init);
491 module_exit(mtk23d_exit);