3335f43eed11106245bbb1c0bdbf8971785a9e67
[firefly-linux-kernel-4.4.55.git] / drivers / misc / 3g_module / mt6229.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 <asm/gpio.h>
17 #include <linux/delay.h>
18 #include <linux/poll.h>
19 #include <linux/wait.h>
20 #include <linux/wakelock.h>
21 #include <linux/workqueue.h>
22 #include <linux/mt6229.h>
23 #include <linux/slab.h>
24 #include <linux/earlysuspend.h>
25
26 MODULE_LICENSE("GPL");
27
28 #define DEBUG
29 #ifdef DEBUG
30 #define MODEMDBG(x...) printk(x)
31 #else
32 #define MODEMDBG(fmt,argss...)
33 #endif
34 #define SLEEP 1
35 #define READY 0
36 static struct wake_lock modem_wakelock;
37 //#define IRQ_BB_WAKEUP_AP_TRIGGER    IRQF_TRIGGER_FALLING
38 #define IRQ_BB_WAKEUP_AP_TRIGGER    IRQF_TRIGGER_RISING
39 #define MT6229_RESET 0x01
40 struct rk29_mt6229_data *gpdata = NULL;
41 struct class *modem_class = NULL; 
42 static int do_wakeup_irq = 0;
43 static int modem_status;
44 static void ap_wakeup_bp(struct platform_device *pdev, int wake)
45 {
46         struct rk29_mt6229_data *pdata = pdev->dev.platform_data;
47  
48           gpio_set_value(pdata->modem_usb_en,wake);
49           if(wake == 1)
50                   wake = 0;
51           else
52                   wake = 1;
53           gpio_set_value(pdata->modem_uart_en,wake);
54
55 }
56 extern void rk28_send_wakeup_key(void);
57
58 static void do_wakeup(struct work_struct *work)
59 {
60                 gpio_set_value(gpdata->ap_ready,GPIO_HIGH);
61                 gpio_set_value(gpdata->modem_usb_en,GPIO_HIGH);
62 }
63
64 static DECLARE_DELAYED_WORK(wakeup_work, do_wakeup);
65 static irqreturn_t detect_irq_handler(int irq, void *dev_id)
66 {
67     if(do_wakeup_irq)
68     {
69         do_wakeup_irq = 0;
70         wake_lock_timeout(&modem_wakelock, 10 * HZ);
71         //schedule_delayed_work(&wakeup_work, 2*HZ);
72     }
73     return IRQ_HANDLED;
74 }
75 int modem_poweron_off(int on_off)
76 {
77         struct rk29_mt6229_data *pdata = gpdata;                
78   if(on_off)
79   {
80                 gpio_set_value(pdata->bp_power, GPIO_LOW);
81                 gpio_set_value(pdata->modem_usb_en, GPIO_HIGH);
82                 gpio_set_value(pdata->modem_uart_en, GPIO_LOW);
83                 gpio_set_value(pdata->ap_ready, GPIO_HIGH);
84   }
85   else
86   {
87                 gpio_set_value(pdata->bp_power, GPIO_HIGH);
88                 gpio_set_value(pdata->modem_usb_en, GPIO_LOW);
89                 gpio_set_value(pdata->modem_uart_en, GPIO_HIGH);
90                 gpio_set_value(pdata->ap_ready, GPIO_LOW);
91   }
92   return 0;
93 }
94 static int mt6229_open(struct inode *inode, struct file *file)
95 {
96         struct rk29_mt6229_data *pdata = gpdata;
97         device_init_wakeup(pdata->dev, 1);
98         return 0;
99 }
100 static ssize_t mt6229_write(struct file *file, const char __user *buf,size_t len, loff_t *off)
101 {
102         static char cmd[2];
103         int ret = 0;
104         if (len > 2) 
105         {
106                 return -EINVAL;
107         }
108         ret = copy_from_user(&cmd, buf, len);
109         if (ret != 0) {
110                 return -EFAULT;
111         }
112         printk(" received cmd = %c\n",cmd[0]);
113         if (cmd[0] == '0')
114         {
115                 gpio_set_value(gpdata->ap_ready, GPIO_LOW);
116         }       
117         if (cmd[0] == '1')
118         {
119                 gpio_set_value(gpdata->ap_ready, GPIO_HIGH);
120         }
121         if (cmd[0] == '2')
122         {
123                 gpio_set_value(gpdata->modem_uart_en, GPIO_LOW);
124         }
125         if (cmd[0] == '3')
126         {
127                 gpio_set_value(gpdata->modem_uart_en, GPIO_HIGH);
128         }
129         if (cmd[0] == '4')
130         {
131                 gpio_set_value(gpdata->modem_usb_en, GPIO_HIGH);
132         }if (cmd[0] == '5')
133         {
134                 gpio_set_value(gpdata->modem_usb_en, GPIO_LOW);
135         }
136         return len;
137 }
138 static int mt6229_release(struct inode *inode, struct file *file)
139 {
140         return 0;
141 }
142
143 static long mt6229_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
144 {
145         struct rk29_mt6229_data *pdata = gpdata;
146         switch(cmd)
147         {
148                 case MT6229_RESET:                                      
149                         gpio_set_value(pdata->bp_power, GPIO_HIGH);
150                         msleep(10);
151                         gpio_set_value(pdata->bp_power, GPIO_LOW);
152                         break;
153                 default:
154                         break;
155         }
156         return 0;
157 }
158
159 static struct file_operations mt6229_fops = {
160         .owner = THIS_MODULE,
161         .open = mt6229_open,
162         .write = mt6229_write,
163         .release = mt6229_release,
164         .unlocked_ioctl = mt6229_ioctl
165 };
166
167 static struct miscdevice mt6229_misc = {
168         .minor = MISC_DYNAMIC_MINOR,
169         .name = MODEM_NAME,
170         .fops = &mt6229_fops
171 };
172 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
173 static ssize_t modem_status_read(struct class *cls, struct class_attribute *attr, char *_buf)
174 #else
175 static ssize_t modem_status_read(struct class *cls, char *_buf)
176 #endif
177 {
178
179         return sprintf(_buf, "%d\n", modem_status);
180         
181 }
182 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37))
183 static ssize_t modem_status_write(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count)
184 #else
185 static ssize_t modem_status_write(struct class *cls, const char *_buf, size_t _count)
186 #endif
187 {
188     int new_state = simple_strtoul(_buf, NULL, 16);
189    if(new_state == modem_status) return _count;
190    if (new_state == 1){
191      printk("%s, c(%d), modem resume \n", __FUNCTION__, new_state);
192      gpio_set_value(gpdata->modem_usb_en, GPIO_HIGH);
193      gpio_set_value(gpdata->modem_uart_en,GPIO_LOW);
194    }else if(new_state == 0){
195      printk("%s, c(%d), modem suspend \n", __FUNCTION__, new_state);
196      gpio_set_value(gpdata->modem_usb_en, GPIO_LOW);
197      gpio_set_value(gpdata->modem_uart_en,GPIO_HIGH);
198    }else{
199      printk("%s, invalid parameter \n", __FUNCTION__);
200    }
201         modem_status = new_state;
202     return _count; 
203 }
204 static CLASS_ATTR(modem_status, 0777, modem_status_read, modem_status_write);
205 static int mt6229_probe(struct platform_device *pdev)
206 {
207         struct rk29_mt6229_data *pdata = gpdata = pdev->dev.platform_data;
208         struct modem_dev *mt6229_data = NULL;
209         int result, irq = 0;    
210         pdata->dev = &pdev->dev;
211         if(pdata->io_init)
212                 pdata->io_init();
213         mt6229_data = kzalloc(sizeof(struct modem_dev), GFP_KERNEL);
214         if(mt6229_data == NULL)
215         {
216                 printk("failed to request mt6229_data\n");
217                 goto err0;
218         }
219         platform_set_drvdata(pdev, mt6229_data);        
220         result = gpio_request(pdata->modem_power_en,"modem_power_en");
221         if(result){
222                         printk("failed to request modem_power_en gpio\n");
223                         goto err1;
224                 }
225         gpio_set_value(pdata->modem_power_en, GPIO_HIGH);
226         msleep(1000);
227   result = gpio_request(pdata->bp_power,"modem_power");
228   if(result){
229                 printk("failed to request modem_power gpio\n");
230                         goto err2;
231         }
232   result = gpio_request(pdata->modem_usb_en, "modem_usb_en");
233         if (result) {
234                 printk("failed to request modem_usb_en gpio\n");
235                 goto err3;
236         }       
237         result = gpio_request(pdata->modem_uart_en,"modem_uart_en");
238         if(result){
239                         printk("failed to request modem_uart_en gpio\n");
240                         goto err4;
241         }
242         result = gpio_request(pdata->bp_wakeup_ap, "bp_wakeup_ap");
243         if (result) {
244                         printk("failed to request bp_wakeup_ap gpio\n");
245                         goto err5;
246         }
247         gpio_direction_input(pdata->bp_wakeup_ap);
248         irq     = gpio_to_irq(pdata->bp_wakeup_ap);
249         if(irq < 0)
250         {
251                 gpio_free(pdata->bp_wakeup_ap);
252                 printk("failed to request bp_wakeup_ap\n");
253         }
254         result = request_irq(irq, detect_irq_handler, IRQ_BB_WAKEUP_AP_TRIGGER, "bp_wakeup_ap", NULL);
255         if (result < 0) {
256                 printk("%s: request_irq(%d) failed\n", __func__, irq);
257                 gpio_free(pdata->bp_wakeup_ap);
258                 goto err5;
259         }
260         enable_irq_wake(irq);
261         wake_lock_init(&modem_wakelock, WAKE_LOCK_SUSPEND, "bp_wakeup_ap");
262         result = gpio_request(pdata->ap_ready, "ap_ready");
263         if (result < 0) {
264                 printk("failed to request ap_ready gpio\n");    
265                 goto err6;
266         }
267
268         modem_poweron_off(1);
269         modem_status = 1;
270          
271         result = misc_register(&mt6229_misc);
272         if(result)
273         {
274                 printk("misc_register err\n");
275         }       
276         return result;
277 err0:
278         kfree(mt6229_data);
279 err1:
280         gpio_free(pdata->modem_power_en);
281 err2:
282         gpio_free(pdata->bp_power);
283 err3:
284         gpio_free(pdata->modem_usb_en);
285 err4:
286         gpio_free(pdata->modem_uart_en);
287 err5:
288         gpio_free(pdata->bp_wakeup_ap);
289 err6:
290         gpio_free(pdata->ap_ready);
291         return 0;
292 }
293
294 int mt6229_suspend(struct platform_device *pdev, pm_message_t state)
295 {
296         do_wakeup_irq = 1;
297         ap_wakeup_bp(pdev, 0);
298         gpio_set_value(gpdata->ap_ready,0);
299         return 0;
300 }
301
302 int mt6229_resume(struct platform_device *pdev)
303 {
304         gpio_set_value(gpdata->modem_uart_en,GPIO_LOW);
305         schedule_delayed_work(&wakeup_work, 2*HZ);
306         return 0;
307 }
308
309 void mt6229_shutdown(struct platform_device *pdev)
310 {
311         struct rk29_mt6229_data *pdata = pdev->dev.platform_data;
312         struct modem_dev *mt6229_data = platform_get_drvdata(pdev);
313         
314         modem_poweron_off(0);
315
316         if(pdata->io_deinit)
317                 pdata->io_deinit();
318         cancel_work_sync(&mt6229_data->work);
319         gpio_free(pdata->modem_power_en);
320         gpio_free(pdata->bp_power);
321         gpio_free(pdata->modem_usb_en);
322         gpio_free(pdata->modem_uart_en);
323         gpio_free(pdata->bp_wakeup_ap);
324         kfree(mt6229_data);
325 }
326
327 static struct platform_driver mt6229_driver = {
328         .probe  = mt6229_probe,
329         .shutdown       = mt6229_shutdown,
330         .suspend        = mt6229_suspend,
331         .resume         = mt6229_resume,
332         .driver = {
333                 .name   = "mt6229",
334                 .owner  = THIS_MODULE,
335         },
336 };
337
338 static int __init mt6229_init(void)
339 {
340         int ret ;
341         modem_class = class_create(THIS_MODULE, "rk291x_modem");
342         ret =  class_create_file(modem_class, &class_attr_modem_status);
343         if (ret)
344         {
345                 printk("Fail to class rk291x_modem.\n");
346         }
347         return platform_driver_register(&mt6229_driver);
348 }
349
350 static void __exit mt6229_exit(void)
351 {
352         platform_driver_unregister(&mt6229_driver);
353         class_remove_file(modem_class, &class_attr_modem_status);
354 }
355
356 module_init(mt6229_init);
357
358 module_exit(mt6229_exit);