Merge remote-tracking branch 'remotes/tegra/android-tegra-2.6.36-honeycomb-mr1' into...
[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                   if(pdata->bp_ap_wakeup) // SDK°åÖУ¬¸Ã¿ÚûÓÐÒý³ö
165                         gpio_direction_input(pdata->bp_ap_wakeup);
166                         
167                         /* ³õʼ»¯BP»½ÐÑAPµÄ¹¦ÄÜ */
168                         wakelock_inited = false;
169                         irq = gpio_to_irq(pdata->bp_statue);
170                         if (irq < 0) {
171                                 printk("can't get pdata->bp_statue irq \n");
172                         }
173                         else
174                         {
175                                 error = request_irq(irq, BBwakeup_isr,
176                                                     IRQF_TRIGGER_FALLING,
177                                                     NULL,
178                                                     pdata);
179                                 if (error) {
180                                         printk("mtk23d_probe bp_statue request_irq error!!! \n");
181                                 }
182                         }
183                         if (!wakelock_inited) {
184                                 wake_lock_init(&mtk23d_wakelock, WAKE_LOCK_SUSPEND, "23d_resume");
185                                 wakelock_inited = true;
186                         }
187   }
188   else
189   {
190                         printk("modem_poweroff\n");
191                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
192                         mdelay(100);
193                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);
194   }
195 }
196 static int power_on =1;
197 static int mtk23d_open(struct inode *inode, struct file *file)
198 {
199         struct rk2818_23d_data *pdata = gpdata;
200         //struct rk2818_23d_data *pdata = gpdata = pdev->dev.platform_data;
201         struct platform_data *pdev = container_of(pdata, struct device, platform_data);
202
203         MODEMDBG("modem_open\n");
204
205         int ret = 0;
206         if(power_on)
207         {
208                 power_on = 0;
209                 modem_poweron_off(1);
210         }
211         device_init_wakeup(&pdev, 1);
212
213         return 0;
214 }
215
216 static int mtk23d_release(struct inode *inode, struct file *file)
217 {
218         MODEMDBG("mtk23d_release\n");
219
220         //gpio_free(pdata->bp_power);
221         return 0;
222 }
223
224 //extern char imei_value[16]; // phc, no find 'imei_value' in rk29 project
225 //char imei_value[16] = {0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5};
226
227 static int mtk23d_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg)
228 {
229         struct rk2818_23d_data *pdata = gpdata;
230         int i;
231         void __user *argp = (void __user *)arg;
232         
233         char SectorBuffer[512];
234         
235         printk("mtk23d_ioctl\n");
236         switch(cmd)
237         {
238                 case MTK23D_RESET:              
239                         printk("MTK23D_RESET\n");
240                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH);
241                         mdelay(100);
242                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
243                         mdelay(300);
244                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_HIGH:GPIO_LOW);
245                         msleep(3000);
246                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);
247                         break;
248                 case MTK23D_IMEI_READ:
249                         printk("MTK23D_IMEI_READ\n");
250                         
251                         GetSNSectorInfo(SectorBuffer); // phc,20110624
252                         
253                         if(copy_to_user(argp, &(SectorBuffer[451]), 16))  // IMEIºó´Ó451Æ«ÒÆ¿ªÊ¼µÄ16bytes£¬µÚÒ»¸öbyteΪ³¤¶È¹Ì¶¨Îª15
254                         {
255                                 printk("ERROR: copy_to_user---%s\n", __FUNCTION__);
256                                 return -EFAULT;
257                         }
258                         //printk("IMEI:%d %d %d %d\n", SectorBuffer[451], SectorBuffer[452], SectorBuffer[453], SectorBuffer[454]);
259                         break;
260                 default:
261                         break;
262         }
263         return 0;
264 }
265
266 static struct file_operations mtk23d_fops = {
267         .owner = THIS_MODULE,
268         .open = mtk23d_open,
269         .release = mtk23d_release,
270         .ioctl = mtk23d_ioctl
271 };
272
273 static struct miscdevice mtk23d_misc = {
274         .minor = MISC_DYNAMIC_MINOR,
275         .name = MODEM_NAME,
276         .fops = &mtk23d_fops
277 };
278
279 static int mtk23d_probe(struct platform_device *pdev)
280 {
281         struct rk2818_23d_data *pdata = gpdata = pdev->dev.platform_data;
282         struct modem_dev *mt6223d_data = NULL;
283         int result, error = 0, irq = 0; 
284         
285         MODEMDBG("mtk23d_probe\n");
286
287         //pdata->io_init();
288
289         mt6223d_data = kzalloc(sizeof(struct modem_dev), GFP_KERNEL);
290         if(NULL == mt6223d_data)
291         {
292                 printk("failed to request mt6223d_data\n");
293                 goto err6;
294         }
295         platform_set_drvdata(pdev, mt6223d_data);
296
297         result = gpio_request(pdata->bp_statue, "mtk23d");
298         if (result) {
299                 printk("failed to request BP_STATUS gpio\n");
300                 goto err5;
301         }
302         
303         result = gpio_request(pdata->ap_statue, "mtk23d");
304         if (result) {
305                 printk("failed to request AP_STATUS gpio\n");
306                 goto err4;
307         }       
308         
309         result = gpio_request(pdata->ap_bp_wakeup, "mtk23d");
310         if (result) {
311                 printk("failed to request AP_BP_WAKEUP gpio\n");
312                 goto err3;
313         }       
314         result = gpio_request(pdata->bp_reset, "mtk23d");
315         if (result) {
316                 printk("failed to request BP_RESET gpio\n");
317                 goto err2;
318         }               
319         result = gpio_request(pdata->bp_power, "mtk23d");
320         if (result) {
321                 printk("failed to request BP_POW_EN gpio\n");
322                 goto err1;
323         }
324         
325         if(pdata->bp_ap_wakeup) // SDK°åÖУ¬¸Ã¿ÚûÓÐÒý³ö
326         {
327                 result = gpio_request(pdata->bp_ap_wakeup, "mtk23d");
328                 if (result) {
329                         printk("failed to request BP_AP_WAKEUP gpio\n");
330                         goto err0;
331                 }               
332         }
333         
334 #if 1 // GPIO³õʼ»¯£¬²¢ÇÒ·Àֹ©µç
335         rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_GPIO1B7);                       
336         gpio_request(RK29_PIN1_PB7, NULL);
337         gpio_direction_output(RK29_PIN1_PB7,GPIO_LOW);
338         gpio_pull_updown(RK29_PIN1_PB7, PullDisable);  // ÏÂÀ­½ûÖ¹
339         
340         rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_GPIO1B6);                
341         gpio_request(RK29_PIN1_PB6, NULL);
342         gpio_direction_output(RK29_PIN1_PB6,GPIO_LOW);  
343         gpio_pull_updown(RK29_PIN1_PB6, PullDisable);  // ÏÂÀ­½ûÖ¹
344         
345         rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_GPIO1C1);                        
346         gpio_request(RK29_PIN1_PC1, NULL);
347         gpio_direction_output(RK29_PIN1_PC1,GPIO_LOW);
348         
349         rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_GPIO1C0);                 
350         gpio_request(RK29_PIN1_PC0, NULL);
351         //gpio_direction_input(RK29_PIN1_PC0);          
352         gpio_direction_output(RK29_PIN1_PC0,GPIO_LOW);
353
354
355   gpio_direction_output(pdata->bp_power, GPIO_LOW);
356         gpio_direction_output(pdata->ap_statue, GPIO_LOW);
357         gpio_direction_output(pdata->ap_bp_wakeup, GPIO_LOW);   
358         gpio_direction_output(pdata->bp_reset, GPIO_LOW);
359         //gpio_direction_output(pdata->bp_statue,GPIO_LOW);
360         gpio_direction_input(pdata->bp_statue);
361         if(pdata->bp_ap_wakeup) // SDK°åÖУ¬¸Ã¿ÚûÓÐÒý³ö
362         {
363                 //gpio_direction_output(pdata->bp_ap_wakeup,GPIO_LOW);
364                 gpio_direction_input(pdata->bp_ap_wakeup);
365         }
366         
367         /*¸´Î»BP*/
368         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH);
369         //mdelay(200);
370         //gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_HIGH:GPIO_LOW);
371 #endif  
372
373         INIT_WORK(&mt6223d_data->work, bpwakeup_work_func_work);
374   power_on = 1;
375         result = misc_register(&mtk23d_misc);
376         if(result)
377         {
378                 MODEMDBG("misc_register err\n");
379         }
380         MODEMDBG("mtk23d_probe ok\n");
381         
382         return result;
383 err0:
384         cancel_work_sync(&mt6223d_data->work);
385         gpio_free(pdata->bp_ap_wakeup);
386 err1:
387         gpio_free(pdata->bp_power);
388 err2:
389         gpio_free(pdata->bp_reset);
390 err3:
391         gpio_free(pdata->ap_bp_wakeup);
392 err4:
393         gpio_free(pdata->ap_statue);
394 err5:
395         gpio_free(pdata->bp_statue);
396 err6:
397         kfree(mt6223d_data);
398 ret:
399         return result;
400 }
401
402 int mtk23d_suspend(struct platform_device *pdev)
403 {
404         int irq, error;
405         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
406         
407         MODEMDBG("%s \n", __FUNCTION__);
408         
409         //enable_irq_wake(irq);
410         ap_sleep(pdev);
411         ap_wakeup_bp(pdev, 0);
412
413         irq = gpio_to_irq(pdata->bp_statue);
414         if (irq < 0) {
415                 printk("can't get pdata->bp_statue irq \n");
416         }
417         else
418         {
419                 printk("enable pdata->bp_statue irq_wake!! \n");
420                 bpstatus_irq_enable = true;
421                 enable_irq_wake(irq);
422         }
423         
424         return 0;
425 }
426
427 int mtk23d_resume(struct platform_device *pdev)
428 {
429         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
430         int irq = 0;
431         
432         MODEMDBG("%s \n", __FUNCTION__);
433         
434         irq = gpio_to_irq(pdata->bp_statue);
435         if(irq)
436         {
437                 printk("disable pdata->bp_statue irq_wake!! \n");
438                 bpstatus_irq_enable = false;
439                 disable_irq_wake(irq);
440         }
441         
442         ap_wakeup(pdev);
443         ap_wakeup_bp(pdev, 1);
444         
445         return 0;
446 }
447
448 void mtk23d_shutdown(struct platform_device *pdev, pm_message_t state)
449 {
450         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
451         struct modem_dev *mt6223d_data = platform_get_drvdata(pdev);
452         
453         MODEMDBG("%s \n", __FUNCTION__);
454
455         modem_poweron_off(0);  // power down
456
457         cancel_work_sync(&mt6223d_data->work);
458         gpio_free(pdata->bp_ap_wakeup);
459         gpio_free(pdata->bp_power);
460         gpio_free(pdata->bp_reset);
461         gpio_free(pdata->ap_bp_wakeup);
462         gpio_free(pdata->ap_statue);
463         gpio_free(pdata->bp_statue);
464         kfree(mt6223d_data);
465 }
466
467 static struct platform_driver mtk23d_driver = {
468         .probe  = mtk23d_probe,
469         .shutdown       = mtk23d_shutdown,
470         .suspend        = mtk23d_suspend,
471         .resume         = mtk23d_resume,
472         .driver = {
473                 .name   = "mtk23d",
474                 .owner  = THIS_MODULE,
475         },
476 };
477
478 static int __init mtk23d_init(void)
479 {
480         MODEMDBG("mtk23d_init ret=%d\n");
481         return platform_driver_register(&mtk23d_driver);
482 }
483
484 static void __exit mtk23d_exit(void)
485 {
486         MODEMDBG("mtk23d_exit\n");
487         platform_driver_unregister(&mtk23d_driver);
488 }
489
490 module_init(mtk23d_init);
491 //late_initcall_sync(mtk23d_init);
492 module_exit(mtk23d_exit);