Merge remote-tracking branch 'aosp/android-3.0' into develop-3.0
[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 #include <linux/slab.h>
27
28 MODULE_LICENSE("GPL");
29
30 #define DEBUG
31 #ifdef DEBUG
32 #define MODEMDBG(x...) printk(x)
33 #else
34 #define MODEMDBG(fmt,argss...)
35 #endif
36 #define MTK23D_POWEROFF 0X00
37 #define MTK23D_RESET 0x01
38 #define MTK23D_POWERON  0x02
39 #define MTK23D_POWER_HIGH 0x03
40 #define MTK23D_IMEI_READ  0x04
41 //#define BP_POW_EN     TCA6424_P02
42 //#define BP_STATUS    RK2818_PIN_PH7    //input  high bp sleep
43 //#define AP_STATUS    RK2818_PIN_PA4    //output high ap sleep
44
45 //#define BP_RESET      TCA6424_P11     //Ryan
46
47 //#define AP_BP_WAKEUP  RK2818_PIN_PF5   //output AP wake up BP used rising edge
48 //#define BP_AP_WAKEUP  RK2818_PIN_PE0  //input BP wake up AP
49
50 static bool bpstatus_irq_enable = false;
51 static bool wakelock_inited;
52 static struct wake_lock mtk23d_wakelock;
53
54 #define SLEEP 1
55 #define READY 0
56
57 //struct modem_dev *mt6223d_data = NULL;
58 struct rk2818_23d_data *gpdata = NULL;
59
60 static int rk29_uart_to_gpio(int uart_id)
61 {
62         if(uart_id == 3) {
63                 rk29_mux_api_set(GPIO2B3_UART3SOUT_NAME, GPIO2L_GPIO2B3);                       
64                 rk29_mux_api_set(GPIO2B2_UART3SIN_NAME, GPIO2L_GPIO2B2);                
65
66                 gpio_request(RK29_PIN2_PB3, NULL);
67                 gpio_request(RK29_PIN2_PB2, NULL);
68
69                 gpio_direction_output(RK29_PIN2_PB3, GPIO_LOW);
70                 gpio_direction_output(RK29_PIN2_PB2, GPIO_LOW);
71         }
72         else if(uart_id == 2) {
73                 rk29_mux_api_set(GPIO2B1_UART2SOUT_NAME, GPIO2L_GPIO2B1);                       
74                 rk29_mux_api_set(GPIO2B0_UART2SIN_NAME, GPIO2L_GPIO2B0);                
75
76                 gpio_request(RK29_PIN2_PB1, NULL);
77                 gpio_request(RK29_PIN2_PB0, NULL);
78
79                 gpio_direction_output(RK29_PIN2_PB1, GPIO_LOW);
80                 gpio_direction_output(RK29_PIN2_PB0, GPIO_LOW);
81         }
82         else if(uart_id == 1) {
83                 rk29_mux_api_set(GPIO2A5_UART1SOUT_NAME, GPIO2L_GPIO2A5);                       
84                 rk29_mux_api_set(GPIO2A4_UART1SIN_NAME, GPIO2L_GPIO2A4);                
85
86                 gpio_request(RK29_PIN2_PA5, NULL);
87                 gpio_request(RK29_PIN2_PA4, NULL);
88
89                 gpio_direction_output(RK29_PIN2_PA5, GPIO_LOW);
90                 gpio_direction_output(RK29_PIN2_PA4, GPIO_LOW);
91         }
92         else if(uart_id == 0){
93                 rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_GPIO1B7);                       
94                 gpio_request(RK29_PIN1_PB7, NULL);
95                 gpio_direction_output(RK29_PIN1_PB7,GPIO_LOW);
96                 gpio_pull_updown(RK29_PIN1_PB7, PullDisable);  // ÏÂÀ­½ûÖ¹
97
98                 rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_GPIO1B6);                
99                 gpio_request(RK29_PIN1_PB6, NULL);
100                 gpio_direction_output(RK29_PIN1_PB6,GPIO_LOW);  
101                 gpio_pull_updown(RK29_PIN1_PB6, PullDisable);  // ÏÂÀ­½ûÖ¹
102
103                 rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_GPIO1C1);                        
104                 gpio_request(RK29_PIN1_PC1, NULL);
105                 gpio_direction_output(RK29_PIN1_PC1,GPIO_LOW);
106
107                 rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_GPIO1C0);                 
108                 gpio_request(RK29_PIN1_PC0, NULL);
109                 //gpio_direction_input(RK29_PIN1_PC0);          
110                 gpio_direction_output(RK29_PIN1_PC0,GPIO_LOW);
111         }
112
113         return 0;
114 }
115
116 static int rk29_gpio_to_uart(int uart_id)
117 {
118         if(uart_id == 3) {
119                 rk29_mux_api_set(GPIO2B3_UART3SOUT_NAME, GPIO2L_UART3_SOUT);
120                 rk29_mux_api_set(GPIO2B2_UART3SIN_NAME, GPIO2L_UART3_SIN); 
121
122                 gpio_request(RK29_PIN2_PB3, NULL);
123                 gpio_request(RK29_PIN2_PB2, NULL);
124
125                 gpio_direction_output(RK29_PIN2_PB3, GPIO_HIGH);
126                 gpio_direction_output(RK29_PIN2_PB2, GPIO_HIGH);
127         }
128         else if(uart_id == 2) {
129                 rk29_mux_api_set(GPIO2B1_UART2SOUT_NAME, GPIO2L_UART2_SOUT);                    
130                 rk29_mux_api_set(GPIO2B0_UART2SIN_NAME, GPIO2L_UART2_SIN);              
131
132                 gpio_request(RK29_PIN2_PB1, NULL);
133                 gpio_request(RK29_PIN2_PB0, NULL);
134
135                 gpio_direction_output(RK29_PIN2_PB1, GPIO_HIGH);
136                 gpio_direction_output(RK29_PIN2_PB0, GPIO_HIGH);
137         }
138         else if(uart_id == 1) {
139                 rk29_mux_api_set(GPIO2A5_UART1SOUT_NAME, GPIO2L_UART1_SOUT);                    
140                 rk29_mux_api_set(GPIO2A4_UART1SIN_NAME, GPIO2L_UART1_SIN);              
141
142                 gpio_request(RK29_PIN2_PA5, NULL);
143                 gpio_request(RK29_PIN2_PA4, NULL);
144
145                 gpio_direction_output(RK29_PIN2_PA5, GPIO_HIGH);
146                 gpio_direction_output(RK29_PIN2_PA4, GPIO_HIGH);
147         }
148         else if(uart_id == 0){
149                 rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_UART0_SOUT);
150                 rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_UART0_SIN); 
151                 rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N);
152                 rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_UART0_CTS_N);     
153         }
154
155         return 0;
156
157 }
158
159 static int  get_bp_statue(struct platform_device *pdev)
160 {
161         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
162         
163         if(gpio_get_value(pdata->bp_statue))
164                 return SLEEP;
165         else
166                 return READY;
167 }
168 static void ap_sleep(struct platform_device *pdev)
169 {
170         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
171         
172         MODEMDBG("ap sleep!\n");
173         gpio_set_value(pdata->ap_statue,GPIO_HIGH);
174 }
175 static void ap_wakeup(struct platform_device *pdev)
176 {
177         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
178         
179         MODEMDBG("ap wakeup!\n");
180         gpio_set_value(pdata->ap_statue,GPIO_LOW);
181 }
182 /* */
183 static void ap_wakeup_bp(struct platform_device *pdev, int wake)//low to wakeup bp
184 {
185         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
186         struct modem_dev *mt6223d_data = platform_get_drvdata(pdev);
187         MODEMDBG("ap_wakeup_bp\n");
188
189         gpio_set_value(pdata->ap_bp_wakeup, wake);  // phc
190         //gpio_set_value(RK2818_PIN_PF5, wake);
191 }
192
193 static void bpwakeup_work_func_work(struct work_struct *work)
194 {
195         struct modem_dev *bdata = container_of(work, struct modem_dev, work);
196         
197         MODEMDBG("%s\n", __FUNCTION__);
198         
199 }
200 /*  */
201 static irqreturn_t  bpwakeup_work_func(int irq, void *data)
202 {
203         struct modem_dev *mt6223d_data = (struct modem_dev *)data;
204         
205         MODEMDBG("bpwakeup_work_func\n");
206         schedule_work(&mt6223d_data->work);
207         return IRQ_HANDLED;
208 }
209 static irqreturn_t  bp_apwakeup_work_func(int irq, void *data)
210 {
211         //struct modem_dev *dev = &mtk23d_misc;
212         
213         MODEMDBG("bp_apwakeup_work_func\n");
214         //wake_up_interruptible(&dev->wakeup);
215         return IRQ_HANDLED;
216 }
217
218 static irqreturn_t BBwakeup_isr(int irq, void *dev_id)
219 {
220         struct rk2818_23d_data *pdata = dev_id;
221         
222         MODEMDBG("%s \n", __FUNCTION__);
223         //if(irq != gpio_to_irq(RK29_PIN1_PC0))
224         //{
225         //              printk("irq != gpio_to_irq(RK29_PIN1_PC0) \n");
226         //              return IRQ_NONE;
227         //}
228         
229 //      disable_irq_wake(irq);
230         
231         if(bpstatus_irq_enable == true)
232         {
233                 MODEMDBG("mtk23d_wakelock 3s \n");
234                 wake_lock_timeout(&mtk23d_wakelock, 3 * HZ);
235         }
236                 
237
238         return IRQ_HANDLED;
239 }
240
241 int modem_poweron_off(int on_off)
242 {
243         struct rk2818_23d_data *pdata = gpdata;
244         int result, error = 0, irq = 0; 
245         
246   if(on_off)
247         {
248                 printk("modem_poweron\n");
249
250                 gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);  // power on enable
251                 mdelay(300);
252                 gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_HIGH:GPIO_LOW);  // release reset
253                 msleep(3000);
254                 gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);  // power on relase
255
256                 rk29_gpio_to_uart(0);
257                 
258                 gpio_direction_input(pdata->bp_statue);
259                 if(pdata->bp_ap_wakeup) // SDK°åÖУ¬¸Ã¿ÚûÓÐÒý³ö
260                 gpio_direction_input(pdata->bp_ap_wakeup);
261
262                 /* ³õʼ»¯BP»½ÐÑAPµÄ¹¦ÄÜ */
263                 wakelock_inited = false;
264                 irq = gpio_to_irq(pdata->bp_statue);
265                 if (irq < 0) {
266                         printk("can't get pdata->bp_statue irq \n");
267                 }
268                 else
269                 {
270                         error = request_irq(irq, BBwakeup_isr,IRQF_TRIGGER_FALLING, "mtk23d", pdata);
271                         if (error) {
272                                 printk("mtk23d_probe bp_statue request_irq error!!! \n");
273                         }
274                 }
275                 if (!wakelock_inited) {
276                         wake_lock_init(&mtk23d_wakelock, WAKE_LOCK_SUSPEND, "23d_resume");
277                         wakelock_inited = true;
278                 }
279         }
280   else
281   {
282                         printk("modem_poweroff\n");
283                         rk29_uart_to_gpio(0);
284                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
285                         msleep(2500);
286                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);
287                         msleep(500);
288                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH); 
289   }
290 }
291 static int power_on =1;
292 static int mtk23d_open(struct inode *inode, struct file *file)
293 {
294         struct rk2818_23d_data *pdata = gpdata;
295         //struct rk2818_23d_data *pdata = gpdata = pdev->dev.platform_data;
296         struct platform_data *pdev = container_of(pdata, struct device, platform_data);
297
298         MODEMDBG("modem_open\n");
299
300         int ret = 0;
301         if(power_on)
302         {
303                 power_on = 0;
304                 modem_poweron_off(1);
305         }
306         device_init_wakeup(&pdev, 1);
307
308         return 0;
309 }
310
311 static int mtk23d_release(struct inode *inode, struct file *file)
312 {
313         MODEMDBG("mtk23d_release\n");
314
315         //gpio_free(pdata->bp_power);
316         return 0;
317 }
318
319 //extern char imei_value[16]; // phc, no find 'imei_value' in rk29 project
320 //char imei_value[16] = {0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5};
321
322 static int mtk23d_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg)
323 {
324         struct rk2818_23d_data *pdata = gpdata;
325         int i,ret;
326         void __user *argp = (void __user *)arg;
327         
328         char SectorBuffer[512];
329         
330         printk("mtk23d_ioctl\n");
331         ret = down_interruptible(&pdata->power_sem);
332         if (ret < 0) {
333                 printk("%s: down power_sem error ret = %d\n", __func__, ret);
334                 return ret;
335         }
336         
337         switch(cmd)
338         {
339
340                 case MTK23D_POWEROFF:
341                         printk("MTK23D_POWEROFF\n");
342                         rk29_uart_to_gpio(0);
343                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
344                         msleep(2500);
345                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);
346                         msleep(500);
347                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH);
348                         break;
349
350                 case MTK23D_RESET:              
351                         printk("MTK23D_RESET\n");
352                         /****power off 23d and uart to gpio***/
353                         rk29_uart_to_gpio(0);
354                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
355                         msleep(2500);
356                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);
357                         msleep(500);
358                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH);
359                         
360                         /****power on 23d***/
361                         msleep(100);
362                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
363                         rk29_gpio_to_uart(0);
364                         msleep(300);
365                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_HIGH:GPIO_LOW);
366                         msleep(2500);
367                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);
368                         break;
369
370                 case MTK23D_POWERON:            
371                         /****power on 23d***/
372                         printk("MTK23D_POWERON\n");
373                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH);
374                         msleep(100);
375                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
376                         rk29_gpio_to_uart(0);
377                         msleep(300);
378                         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_HIGH:GPIO_LOW);
379                         msleep(2500);
380                         gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW);
381                         break;
382                         
383                 case MTK23D_IMEI_READ:
384                         printk("MTK23D_IMEI_READ\n");
385                         
386                         GetSNSectorInfo(SectorBuffer); // phc,20110624
387                         
388                         if(copy_to_user(argp, &(SectorBuffer[451]), 16))  // IMEIºó´Ó451Æ«ÒÆ¿ªÊ¼µÄ16bytes£¬µÚÒ»¸öbyteΪ³¤¶È¹Ì¶¨Îª15
389                         {
390                                 printk("ERROR: copy_to_user---%s\n", __FUNCTION__);
391                                 up(&pdata->power_sem);
392                                 return -EFAULT;
393                         }
394                         //printk("IMEI:%d %d %d %d\n", SectorBuffer[451], SectorBuffer[452], SectorBuffer[453], SectorBuffer[454]);
395                         break;
396                 default:
397                         break;
398         }
399
400         up(&pdata->power_sem);
401         
402         return 0;
403 }
404
405 static struct file_operations mtk23d_fops = {
406         .owner = THIS_MODULE,
407         .open = mtk23d_open,
408         .release = mtk23d_release,
409         .unlocked_ioctl = mtk23d_ioctl
410 };
411
412 static struct miscdevice mtk23d_misc = {
413         .minor = MISC_DYNAMIC_MINOR,
414         .name = MODEM_NAME,
415         .fops = &mtk23d_fops
416 };
417
418 static int mtk23d_probe(struct platform_device *pdev)
419 {
420         struct rk2818_23d_data *pdata = gpdata = pdev->dev.platform_data;
421         struct modem_dev *mt6223d_data = NULL;
422         int result, error = 0, irq = 0; 
423         
424         MODEMDBG("mtk23d_probe\n");
425
426         //pdata->io_init();
427         pdata->dev = &pdev->dev;
428
429         mt6223d_data = kzalloc(sizeof(struct modem_dev), GFP_KERNEL);
430         if(NULL == mt6223d_data)
431         {
432                 printk("failed to request mt6223d_data\n");
433                 goto err6;
434         }
435         platform_set_drvdata(pdev, mt6223d_data);
436
437         result = gpio_request(pdata->bp_statue, "mtk23d");
438         if (result) {
439                 printk("failed to request BP_STATUS gpio\n");
440                 goto err5;
441         }
442         
443         result = gpio_request(pdata->ap_statue, "mtk23d");
444         if (result) {
445                 printk("failed to request AP_STATUS gpio\n");
446                 goto err4;
447         }       
448         
449         result = gpio_request(pdata->ap_bp_wakeup, "mtk23d");
450         if (result) {
451                 printk("failed to request AP_BP_WAKEUP gpio\n");
452                 goto err3;
453         }       
454         result = gpio_request(pdata->bp_reset, "mtk23d");
455         if (result) {
456                 printk("failed to request BP_RESET gpio\n");
457                 goto err2;
458         }               
459         result = gpio_request(pdata->bp_power, "mtk23d");
460         if (result) {
461                 printk("failed to request BP_POW_EN gpio\n");
462                 goto err1;
463         }
464         
465         if(pdata->bp_ap_wakeup) // SDK°åÖУ¬¸Ã¿ÚûÓÐÒý³ö
466         {
467                 result = gpio_request(pdata->bp_ap_wakeup, "mtk23d");
468                 if (result) {
469                         printk("failed to request BP_AP_WAKEUP gpio\n");
470                         goto err0;
471                 }               
472         }
473         
474 #if 1 // GPIO³õʼ»¯£¬²¢ÇÒ·Àֹ©µç
475         rk29_uart_to_gpio(0);
476
477         /***power off 23d***/
478         gpio_direction_output(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH);
479         
480         gpio_direction_output(pdata->ap_statue, GPIO_LOW);
481         gpio_direction_output(pdata->ap_bp_wakeup, GPIO_LOW);   
482         //gpio_direction_output(pdata->bp_statue,GPIO_LOW);
483         gpio_direction_input(pdata->bp_statue);
484         if(pdata->bp_ap_wakeup) // SDK°åÖУ¬¸Ã¿ÚûÓÐÒý³ö
485         {
486                 //gpio_direction_output(pdata->bp_ap_wakeup,GPIO_LOW);
487                 gpio_direction_input(pdata->bp_ap_wakeup);
488         }
489
490         /*¸´Î»BP*/
491         gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH);
492         //mdelay(200);
493         //gpio_set_value(pdata->bp_reset, pdata->bp_reset_active_low? GPIO_HIGH:GPIO_LOW);
494 #endif  
495
496         INIT_WORK(&mt6223d_data->work, bpwakeup_work_func_work);
497         sema_init(&pdata->power_sem,1);
498         power_on = 1;
499         result = misc_register(&mtk23d_misc);
500         if(result)
501         {
502                 MODEMDBG("misc_register err\n");
503         }
504         MODEMDBG("mtk23d_probe ok\n");
505         
506         return result;
507 err0:
508         cancel_work_sync(&mt6223d_data->work);
509         gpio_free(pdata->bp_ap_wakeup);
510 err1:
511         gpio_free(pdata->bp_power);
512 err2:
513         gpio_free(pdata->bp_reset);
514 err3:
515         gpio_free(pdata->ap_bp_wakeup);
516 err4:
517         gpio_free(pdata->ap_statue);
518 err5:
519         gpio_free(pdata->bp_statue);
520 err6:
521         kfree(mt6223d_data);
522 ret:
523         return result;
524 }
525
526 int mtk23d_suspend(struct platform_device *pdev)
527 {
528         int irq, error;
529         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
530         
531         MODEMDBG("%s \n", __FUNCTION__);
532         
533         //enable_irq_wake(irq);
534         ap_sleep(pdev);
535         ap_wakeup_bp(pdev, 0);
536
537         irq = gpio_to_irq(pdata->bp_statue);
538         if (irq < 0) {
539                 printk("can't get pdata->bp_statue irq \n");
540         }
541         else
542         {
543                 printk("enable pdata->bp_statue irq_wake!! \n");
544                 bpstatus_irq_enable = true;
545                 enable_irq_wake(irq);
546         }
547         
548         return 0;
549 }
550
551 int mtk23d_resume(struct platform_device *pdev)
552 {
553         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
554         int irq = 0;
555         
556         MODEMDBG("%s \n", __FUNCTION__);
557         
558         irq = gpio_to_irq(pdata->bp_statue);
559         if(irq)
560         {
561                 printk("disable pdata->bp_statue irq_wake!! \n");
562                 bpstatus_irq_enable = false;
563                 disable_irq_wake(irq);
564         }
565         
566         ap_wakeup(pdev);
567         ap_wakeup_bp(pdev, 1);
568         
569         return 0;
570 }
571
572 void mtk23d_shutdown(struct platform_device *pdev, pm_message_t state)
573 {
574         struct rk2818_23d_data *pdata = pdev->dev.platform_data;
575         struct modem_dev *mt6223d_data = platform_get_drvdata(pdev);
576         
577         MODEMDBG("%s \n", __FUNCTION__);
578
579         modem_poweron_off(0);  // power down
580
581         cancel_work_sync(&mt6223d_data->work);
582         gpio_free(pdata->bp_ap_wakeup);
583         gpio_free(pdata->bp_power);
584         gpio_free(pdata->bp_reset);
585         gpio_free(pdata->ap_bp_wakeup);
586         gpio_free(pdata->ap_statue);
587         gpio_free(pdata->bp_statue);
588         kfree(mt6223d_data);
589 }
590
591 static struct platform_driver mtk23d_driver = {
592         .probe  = mtk23d_probe,
593         .shutdown       = mtk23d_shutdown,
594         .suspend        = mtk23d_suspend,
595         .resume         = mtk23d_resume,
596         .driver = {
597                 .name   = "mtk23d",
598                 .owner  = THIS_MODULE,
599         },
600 };
601
602 static int __init mtk23d_init(void)
603 {
604         MODEMDBG("mtk23d_init ret=%d\n");
605         return platform_driver_register(&mtk23d_driver);
606 }
607
608 static void __exit mtk23d_exit(void)
609 {
610         MODEMDBG("mtk23d_exit\n");
611         platform_driver_unregister(&mtk23d_driver);
612 }
613
614 module_init(mtk23d_init);
615 //late_initcall_sync(mtk23d_init);
616 module_exit(mtk23d_exit);