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
25 #include <linux/bp-auto.h>
\r
28 #define DBG(x...) printk(x)
\r
33 struct bp_private_data *g_bp;
\r
34 static struct class *g_bp_class;
\r
35 static struct bp_operate *g_bp_ops[BP_ID_NUM];
\r
36 struct class *bp_class = NULL;
\r
38 static void ap_wakeup_bp(struct bp_private_data *bp, int wake)
\r
40 if(bp->ops->ap_wake_bp)
\r
41 bp->ops->ap_wake_bp(bp, wake);
\r
45 static int bp_request_gpio(struct bp_private_data *bp)
\r
49 if(bp->pdata->gpio_valid)
\r
51 if(bp->pdata->bp_power > 0)
\r
53 bp->ops->bp_power = bp->pdata->bp_power;
\r
56 if(bp->pdata->bp_en > 0)
\r
58 bp->ops->bp_en = bp->pdata->bp_en;
\r
61 if(bp->pdata->bp_reset > 0)
\r
63 bp->ops->bp_reset = bp->pdata->bp_reset;
\r
66 if(bp->pdata->ap_ready > 0)
\r
68 bp->ops->ap_ready = bp->pdata->ap_ready;
\r
71 if(bp->pdata->bp_ready > 0)
\r
73 bp->ops->bp_ready = bp->pdata->bp_ready;
\r
76 if(bp->pdata->ap_wakeup_bp > 0)
\r
78 bp->ops->ap_wakeup_bp = bp->pdata->ap_wakeup_bp;
\r
81 if(bp->pdata->bp_wakeup_ap > 0)
\r
83 bp->ops->bp_wakeup_ap = bp->pdata->bp_wakeup_ap;
\r
86 if(bp->pdata->bp_usb_en > 0)
\r
88 bp->ops->bp_usb_en = bp->pdata->bp_usb_en;
\r
91 if(bp->pdata->bp_uart_en > 0)
\r
93 bp->ops->bp_uart_en = bp->pdata->bp_uart_en;
\r
98 if(bp->ops->bp_power != BP_UNKNOW_DATA)
\r
100 result = gpio_request(bp->ops->bp_power, "bp_power");
\r
103 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_power);
\r
108 if(bp->ops->bp_en != BP_UNKNOW_DATA)
\r
110 result = gpio_request(bp->ops->bp_en, "bp_en");
\r
113 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_en);
\r
119 if(bp->ops->bp_reset != BP_UNKNOW_DATA)
\r
121 result = gpio_request(bp->ops->bp_reset, "bp_reset");
\r
124 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_reset);
\r
130 if(bp->ops->ap_ready != BP_UNKNOW_DATA)
\r
132 result = gpio_request(bp->ops->ap_ready, "ap_ready");
\r
135 printk("%s:fail to request gpio %d\n",__func__, bp->ops->ap_ready);
\r
141 if(bp->ops->bp_ready != BP_UNKNOW_DATA)
\r
143 result = gpio_request(bp->ops->bp_ready, "bp_ready");
\r
146 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_ready);
\r
152 if(bp->ops->ap_wakeup_bp != BP_UNKNOW_DATA)
\r
154 result = gpio_request(bp->ops->ap_wakeup_bp, "ap_wakeup_bp");
\r
157 printk("%s:fail to request gpio %d\n",__func__, bp->ops->ap_wakeup_bp);
\r
162 if(bp->ops->bp_wakeup_ap != BP_UNKNOW_DATA)
\r
164 result = gpio_request(bp->ops->bp_wakeup_ap, "bp_wakeup_ap");
\r
167 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_wakeup_ap);
\r
172 if(bp->ops->bp_usb_en != BP_UNKNOW_DATA)
\r
174 result = gpio_request(bp->ops->bp_usb_en, "bp_usb_en");
\r
177 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_usb_en);
\r
182 if(bp->ops->bp_uart_en != BP_UNKNOW_DATA)
\r
184 result = gpio_request(bp->ops->bp_uart_en, "bp_uart_en");
\r
187 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_uart_en);
\r
196 static irqreturn_t bp_wake_up_irq(int irq, void *dev_id)
\r
199 struct bp_private_data *bp = dev_id;
\r
200 if(bp->ops->bp_wake_ap)
\r
201 bp->ops->bp_wake_ap(bp);
\r
203 return IRQ_HANDLED;
\r
206 static int bp_id_open(struct inode *inode, struct file *file)
\r
208 struct bp_private_data *bp = g_bp;
\r
213 static int bp_id_release(struct inode *inode, struct file *file)
\r
219 static long bp_id_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
\r
221 struct bp_private_data *bp = g_bp;
\r
222 void __user *argp = (void __user *)arg;
\r
227 case BP_IOCTL_SET_PVID:
\r
231 case BP_IOCTL_GET_BPID:
\r
232 if (copy_to_user(argp, &bp->ops->bp_id, sizeof(bp->ops->bp_id)))
\r
234 printk("%s:failed to copy status to user space.\n",__FUNCTION__);
\r
248 static int bp_dev_open(struct inode *inode, struct file *file)
\r
250 struct bp_private_data *bp = g_bp;
\r
251 device_init_wakeup(bp->dev, 1);
\r
254 static ssize_t bp_dev_write(struct file *file, const char __user *buf,size_t len, loff_t *off)
\r
256 static char cmd[2];
\r
257 struct bp_private_data *bp = g_bp;
\r
264 ret = copy_from_user(&cmd, buf, len);
268 printk(" received cmd = %c\n",cmd[0]);
\r
269 switch(bp->ops->bp_id)
\r
274 gpio_direction_output(bp->ops->ap_ready, GPIO_LOW);
\r
278 gpio_direction_output(bp->ops->ap_ready, GPIO_HIGH);
\r
282 gpio_direction_output(bp->ops->bp_uart_en, GPIO_LOW);
\r
286 gpio_direction_output(bp->ops->bp_uart_en, GPIO_HIGH);
\r
290 gpio_direction_output(bp->ops->bp_usb_en, GPIO_HIGH);
\r
291 }if (cmd[0] == '5')
\r
293 gpio_direction_output(bp->ops->bp_usb_en, GPIO_LOW);
\r
306 static int bp_dev_release(struct inode *inode, struct file *file)
\r
311 static long bp_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
\r
313 struct bp_private_data *bp = g_bp;
\r
314 void __user *argp = (void __user *)arg;
\r
319 case BP_IOCTL_RESET:
\r
322 bp->ops->reset(bp);
\r
324 else if(bp->ops->active)
\r
326 bp->ops->active(bp, 0);
\r
328 bp->ops->active(bp, 1);
\r
332 case BP_IOCTL_POWON:
\r
333 if(bp->ops->active)
\r
334 bp->ops->active(bp, 1);
\r
337 case BP_IOCTL_POWOFF:
\r
338 if(bp->ops->active)
\r
339 bp->ops->active(bp, 0);
\r
342 case BP_IOCTL_WRITE_STATUS:
\r
346 case BP_IOCTL_GET_STATUS:
\r
350 case BP_IOCTL_SET_PVID:
\r
354 case BP_IOCTL_GET_BPID:
\r
355 if (copy_to_user(argp, &bp->ops->bp_id, sizeof(bp->ops->bp_id)))
\r
357 printk("%s:failed to copy status to user space.\n",__FUNCTION__);
\r
370 static ssize_t bp_status_read(struct class *cls, struct class_attribute *attr, char *_buf)
\r
372 struct bp_private_data *bp = g_bp;
\r
374 return sprintf(_buf, "%d\n", bp->status);
\r
378 static ssize_t bp_status_write(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count)
\r
380 struct bp_private_data *bp = g_bp;
\r
384 status = simple_strtoul(_buf, NULL, 16);
\r
385 if(status == bp->status)
\r
388 bp->status = status;
\r
390 if(bp->ops->write_status)
\r
391 result = bp->ops->write_status(bp);
\r
395 static CLASS_ATTR(bp_status, 0777, bp_status_read, bp_status_write);
\r
396 static int bp_probe(struct platform_device *pdev)
\r
398 struct bp_platform_data *pdata = pdev->dev.platform_data;
\r
399 struct bp_private_data *bp = NULL;
\r
400 int i = 0, result;
\r
405 DBG("%s:init start\n",__func__);
\r
407 if(pdata->init_platform_hw)
\r
408 pdata->init_platform_hw();
\r
410 bp = kzalloc(sizeof(struct bp_private_data), GFP_KERNEL);
\r
413 printk("%s:fail malloc bp data\n",__func__);
\r
418 bp->dev = &pdev->dev;
\r
420 //select modem acccording to pdata defaultly
\r
421 if((pdata->bp_id > BP_ID_INVALID) && (pdata->bp_id < BP_ID_NUM))
\r
423 if(g_bp_ops[pdata->bp_id])
\r
425 bp->ops = g_bp_ops[pdata->bp_id];
\r
426 printk("%s:bp_id=%d\n",__func__,bp->ops->bp_id);
\r
430 printk("%s:error:g_bp_ops[%d] = 0x%p\n",__func__, pdata->bp_id, g_bp_ops[pdata->bp_id]);
\r
436 printk("%s:bp_id=%d is out of range\n",__func__, pdata->bp_id);
\r
439 bp_request_gpio(bp);
\r
441 if((bp->ops->bp_wakeup_ap) && (bp->ops->trig != BP_UNKNOW_DATA))
\r
443 result = request_irq(bp->ops->bp_wakeup_ap, bp_wake_up_irq, bp->ops->trig, "bp_wakeup_ap", bp);
\r
445 printk("%s: request_irq(%d) failed\n", __func__, bp->ops->bp_wakeup_ap);
\r
446 gpio_free(pdata->bp_wakeup_ap);
\r
454 enable_irq_wake(bp->ops->bp_wakeup_ap);
\r
455 wake_lock_init(&bp->bp_wakelock, WAKE_LOCK_SUSPEND, "bp_wakelock");
\r
457 bp->status = BP_OFF;
\r
459 if(!bp->ops->private_miscdev)
\r
461 bp->fops.owner = THIS_MODULE;
\r
462 bp->fops.open = bp_dev_open;
\r
463 bp->fops.write = bp_dev_write;
\r
464 bp->fops.release = bp_dev_release;
\r
465 bp->fops.unlocked_ioctl = bp_dev_ioctl;
\r
467 bp->miscdev.minor = MISC_DYNAMIC_MINOR;
\r
468 if(bp->ops->misc_name)
\r
469 bp->miscdev.name = bp->ops->misc_name;
\r
471 bp->miscdev.name = "bp-auto";
\r
472 bp->miscdev.fops = &bp->fops;
\r
476 memcpy(&bp->miscdev, bp->ops->private_miscdev, sizeof(*bp->ops->private_miscdev));
\r
480 result = misc_register(&bp->miscdev);
\r
482 printk("misc_register err\n");
\r
486 bp->id_fops.owner = THIS_MODULE;
\r
487 bp->id_fops.open = bp_id_open;
\r
488 bp->id_fops.release = bp_id_release;
\r
489 bp->id_fops.unlocked_ioctl = bp_id_ioctl;
\r
491 bp->id_miscdev.minor = MISC_DYNAMIC_MINOR;
\r
492 bp->id_miscdev.name = "bp_id";
\r
493 bp->id_miscdev.fops = &bp->id_fops;
\r
494 result = misc_register(&bp->id_miscdev);
\r
496 printk("misc_register err\n");
\r
502 platform_set_drvdata(pdev, bp);
\r
504 printk("%s:init success\n",__func__);
\r
509 int bp_suspend(struct platform_device *pdev, pm_message_t state)
\r
511 struct bp_private_data *bp = platform_get_drvdata(pdev);
\r
513 if(bp->ops->suspend)
\r
514 bp->ops->suspend(bp);
\r
519 int bp_resume(struct platform_device *pdev)
\r
521 struct bp_private_data *bp = platform_get_drvdata(pdev);
\r
523 if(bp->ops->resume)
\r
524 bp->ops->resume(bp);
\r
529 void bp_shutdown(struct platform_device *pdev)
\r
531 struct bp_private_data *bp = platform_get_drvdata(pdev);
\r
533 if(bp->ops->shutdown)
\r
534 bp->ops->shutdown(bp);
\r
539 int bp_register_slave(struct bp_private_data *bp,
\r
540 struct bp_platform_data *slave_pdata,
\r
541 struct bp_operate *(*get_bp_ops)(void))
\r
544 struct bp_operate *ops = get_bp_ops();
\r
545 if((ops->bp_id >= BP_ID_NUM) || (ops->bp_id <= BP_ID_INVALID))
\r
547 printk("%s:%s id is error %d\n", __func__, ops->name, ops->bp_id);
\r
550 g_bp_ops[ops->bp_id] = ops;
\r
551 printk("%s:%s,id=%d\n",__func__,g_bp_ops[ops->bp_id]->name, ops->bp_id);
\r
556 int bp_unregister_slave(struct bp_private_data *bp,
\r
557 struct bp_platform_data *slave_pdata,
\r
558 struct bp_operate *(*get_bp_ops)(void))
\r
561 struct bp_operate *ops = get_bp_ops();
\r
562 if((ops->bp_id >= BP_ID_NUM) || (ops->bp_id <= BP_ID_INVALID))
\r
564 printk("%s:%s id is error %d\n", __func__, ops->name, ops->bp_id);
\r
567 printk("%s:%s,id=%d\n",__func__,g_bp_ops[ops->bp_id]->name, ops->bp_id);
\r
568 g_bp_ops[ops->bp_id] = NULL;
\r
573 static struct platform_driver bp_driver = {
\r
575 .shutdown = bp_shutdown,
\r
576 .suspend = bp_suspend,
\r
577 .resume = bp_resume,
\r
580 .owner = THIS_MODULE,
\r
584 static int __init bp_init(void)
\r
587 bp_class = class_create(THIS_MODULE, "bp-auto");
\r
588 ret = class_create_file(bp_class, &class_attr_bp_status);
\r
591 printk("Fail to create class bp-auto\n");
\r
593 return platform_driver_register(&bp_driver);
\r
596 static void __exit bp_exit(void)
\r
598 platform_driver_unregister(&bp_driver);
\r
599 class_remove_file(bp_class, &class_attr_bp_status);
\r
602 module_init(bp_init);
\r
603 module_exit(bp_exit);
\r
605 MODULE_AUTHOR("ROCKCHIP Corporation:lw@rock-chips.com");
\r
606 MODULE_DESCRIPTION("device interface for auto modem driver");
\r
607 MODULE_LICENSE("GPL");
\r