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
26 #include "../../mtd/rknand/api_flash.h"
\r
29 #define DBG(x...) printk(x)
\r
34 struct bp_private_data *g_bp;
\r
35 static struct class *g_bp_class;
\r
36 static struct bp_operate *g_bp_ops[BP_ID_NUM];
\r
37 struct class *bp_class = NULL;
\r
38 int get_current_bp_id(){
\r
39 return g_bp->ops->bp_id;
\r
41 static void ap_wakeup_bp(struct bp_private_data *bp, int wake)
\r
43 if(bp->ops->ap_wake_bp)
\r
44 bp->ops->ap_wake_bp(bp, wake);
\r
48 static int bp_request_gpio(struct bp_private_data *bp)
\r
52 if(bp->pdata->gpio_valid)
\r
54 if(bp->pdata->bp_power > 0)
\r
56 bp->ops->bp_power = bp->pdata->bp_power;
\r
59 if(bp->pdata->bp_en > 0)
\r
61 bp->ops->bp_en = bp->pdata->bp_en;
\r
64 if(bp->pdata->bp_reset > 0)
\r
66 bp->ops->bp_reset = bp->pdata->bp_reset;
\r
69 if(bp->pdata->ap_ready > 0)
\r
71 bp->ops->ap_ready = bp->pdata->ap_ready;
\r
74 if(bp->pdata->bp_ready > 0)
\r
76 bp->ops->bp_ready = bp->pdata->bp_ready;
\r
79 if(bp->pdata->ap_wakeup_bp > 0)
\r
81 bp->ops->ap_wakeup_bp = bp->pdata->ap_wakeup_bp;
\r
84 if(bp->pdata->bp_wakeup_ap > 0)
\r
86 bp->ops->bp_wakeup_ap = bp->pdata->bp_wakeup_ap;
\r
89 if(bp->pdata->bp_usb_en > 0)
\r
91 bp->ops->bp_usb_en = bp->pdata->bp_usb_en;
\r
94 if(bp->pdata->bp_uart_en > 0)
\r
96 bp->ops->bp_uart_en = bp->pdata->bp_uart_en;
\r
101 if(bp->ops->bp_power != BP_UNKNOW_DATA)
\r
103 result = gpio_request(bp->ops->bp_power, "bp_power");
\r
106 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_power);
\r
111 if(bp->ops->bp_en != BP_UNKNOW_DATA)
\r
113 result = gpio_request(bp->ops->bp_en, "bp_en");
\r
116 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_en);
\r
122 if(bp->ops->bp_reset != BP_UNKNOW_DATA)
\r
124 result = gpio_request(bp->ops->bp_reset, "bp_reset");
\r
127 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_reset);
\r
133 if(bp->ops->ap_ready != BP_UNKNOW_DATA)
\r
135 result = gpio_request(bp->ops->ap_ready, "ap_ready");
\r
138 printk("%s:fail to request gpio %d\n",__func__, bp->ops->ap_ready);
\r
144 if(bp->ops->bp_ready != BP_UNKNOW_DATA)
\r
146 result = gpio_request(bp->ops->bp_ready, "bp_ready");
\r
149 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_ready);
\r
155 if(bp->ops->ap_wakeup_bp != BP_UNKNOW_DATA)
\r
157 result = gpio_request(bp->ops->ap_wakeup_bp, "ap_wakeup_bp");
\r
160 printk("%s:fail to request gpio %d\n",__func__, bp->ops->ap_wakeup_bp);
\r
165 if(bp->ops->bp_wakeup_ap != BP_UNKNOW_DATA)
\r
167 result = gpio_request(bp->ops->bp_wakeup_ap, "bp_wakeup_ap");
\r
170 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_wakeup_ap);
\r
175 if(bp->ops->bp_usb_en != BP_UNKNOW_DATA)
\r
177 result = gpio_request(bp->ops->bp_usb_en, "bp_usb_en");
\r
180 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_usb_en);
\r
185 if(bp->ops->bp_uart_en != BP_UNKNOW_DATA)
\r
187 result = gpio_request(bp->ops->bp_uart_en, "bp_uart_en");
\r
190 printk("%s:fail to request gpio %d\n",__func__, bp->ops->bp_uart_en);
\r
199 static irqreturn_t bp_wake_up_irq(int irq, void *dev_id)
\r
202 struct bp_private_data *bp = dev_id;
\r
203 printk("<---%s:bp_id=%d--->\n",__FUNCTION__,bp->ops->bp_id);
\r
204 if(bp->ops->bp_wake_ap){
\r
205 bp->ops->bp_wake_ap(bp);
\r
207 return IRQ_HANDLED;
\r
210 static int bp_id_open(struct inode *inode, struct file *file)
\r
212 struct bp_private_data *bp = g_bp;
\r
217 static int bp_id_release(struct inode *inode, struct file *file)
\r
223 static long bp_id_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
\r
225 struct bp_private_data *bp = g_bp;
\r
226 void __user *argp = (void __user *)arg;
\r
231 case BP_IOCTL_SET_PVID:
\r
235 case BP_IOCTL_GET_BPID:
\r
236 if (copy_to_user(argp, &bp->ops->bp_id, sizeof(bp->ops->bp_id)))
\r
238 printk("%s:failed to copy status to user space.\n",__FUNCTION__);
\r
252 static int bp_dev_open(struct inode *inode, struct file *file)
\r
254 struct bp_private_data *bp = g_bp;
\r
255 printk("<---%s:bp_id=%d--->\n",__FUNCTION__,bp->ops->bp_id);
\r
256 device_init_wakeup(bp->dev, 1);
\r
259 static ssize_t bp_dev_write(struct file *file, const char __user *buf,size_t len, loff_t *off)
\r
261 static char cmd[2];
\r
262 struct bp_private_data *bp = g_bp;
\r
269 ret = copy_from_user(&cmd, buf, len);
\r
273 printk(" received cmd = %c\n",cmd[0]);
\r
274 switch(bp->ops->bp_id)
\r
279 gpio_direction_output(bp->ops->ap_ready, GPIO_LOW);
\r
283 gpio_direction_output(bp->ops->ap_ready, GPIO_HIGH);
\r
287 gpio_direction_output(bp->ops->bp_uart_en, GPIO_LOW);
\r
291 gpio_direction_output(bp->ops->bp_uart_en, GPIO_HIGH);
\r
295 gpio_direction_output(bp->ops->bp_usb_en, GPIO_HIGH);
\r
296 }if (cmd[0] == '5')
\r
298 gpio_direction_output(bp->ops->bp_usb_en, GPIO_LOW);
\r
311 static int bp_dev_release(struct inode *inode, struct file *file)
\r
313 struct bp_private_data *bp = g_bp;
\r
314 printk("<---%s:bp_id=%d--->\n",__FUNCTION__,bp->ops->bp_id);
\r
319 static long bp_dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
\r
321 struct bp_private_data *bp = g_bp;
\r
322 void __user *argp = (void __user *)arg;
\r
323 char SectorBuffer[512];
\r
325 printk("<---%s:bp_id=%d,cmd=%d--->\n",__FUNCTION__,bp->ops->bp_id,cmd);
\r
328 case BP_IOCTL_RESET:
\r
331 bp->ops->reset(bp);
\r
335 case BP_IOCTL_POWON:
\r
336 if(bp->ops->active)
\r
337 bp->ops->active(bp, 1);
\r
338 bp->status = BP_ON;
\r
341 case BP_IOCTL_POWOFF:
\r
342 if(bp->ops->active)
\r
343 bp->ops->active(bp, 0);
\r
344 bp->status = BP_OFF;
\r
347 case BP_IOCTL_WRITE_STATUS:
\r
351 case BP_IOCTL_GET_STATUS:
\r
355 case BP_IOCTL_SET_PVID:
\r
359 case BP_IOCTL_GET_BPID:
\r
360 if (copy_to_user(argp, &bp->ops->bp_id, sizeof(bp->ops->bp_id)))
\r
362 printk("%s:failed to copy status to user space.\n",__FUNCTION__);
\r
367 case BP_IOCTL_GET_IMEI:
\r
368 printk("BP_IMEI_READ\n");
\r
369 GetSNSectorInfo(SectorBuffer);
\r
370 if(copy_to_user(argp, &(SectorBuffer[451]), 16)) // IMEIo¨®¡ä¨®451??¨°??a¨º?¦Ì?16bytes¡ê?¦Ì¨²¨°???byte?a3¡è?¨¨1¨¬?¡§?a15
\r
372 printk("ERROR: copy_to_user---%s\n", __FUNCTION__);
\r
384 static ssize_t bp_status_read(struct class *cls, struct class_attribute *attr, char *_buf)
\r
386 struct bp_private_data *bp = g_bp;
\r
388 return sprintf(_buf, "%d\n", bp->status);
\r
392 static ssize_t bp_status_write(struct class *cls, struct class_attribute *attr, const char *_buf, size_t _count)
\r
394 struct bp_private_data *bp = g_bp;
\r
398 status = simple_strtoul(_buf, NULL, 16);
\r
399 printk("<<<<<<<<--%s:buf:%s,status=%d\n",__func__,_buf,status);
\r
401 if(status == bp->status)
\r
404 bp->status = status;
\r
405 if(bp->ops->write_status){
\r
406 result = bp->ops->write_status(bp);
\r
410 case 1://modem power on
\r
411 if(bp->ops->active)
\r
412 bp->ops->active(bp, 1);
\r
415 case 0: // modem power off
\r
416 if(bp->ops->active)
\r
417 bp->ops->active(bp, 0);
\r
426 //static CLASS_ATTR(bp_status, 0777, bp_status_read, bp_status_write);
\r
427 static int bp_probe(struct platform_device *pdev)
\r
429 struct bp_platform_data *pdata = pdev->dev.platform_data;
\r
430 struct bp_private_data *bp = NULL;
\r
431 int i = 0, result,irq = 0;
\r
435 DBG("%s:init start\n",__func__);
\r
437 if(pdata->init_platform_hw)
\r
438 pdata->init_platform_hw();
\r
439 if(pdata->get_bp_id())
\r
440 pdata->bp_id = pdata->get_bp_id();
\r
441 bp = kzalloc(sizeof(struct bp_private_data), GFP_KERNEL);
\r
444 printk("%s:fail malloc bp data\n",__func__);
\r
449 bp->dev = &pdev->dev;
\r
451 //select modem acccording to pdata defaultly
\r
452 if((pdata->bp_id > BP_ID_INVALID) && (pdata->bp_id < BP_ID_NUM))
\r
454 if(g_bp_ops[pdata->bp_id])
\r
456 bp->ops = g_bp_ops[pdata->bp_id];
\r
457 printk("%s:bp_id=%d\n",__func__,bp->ops->bp_id);
\r
461 printk("%s:error:g_bp_ops[%d] = 0x%p\n",__func__, pdata->bp_id, g_bp_ops[pdata->bp_id]);
\r
467 printk("%s:bp_id=%d is out of range\n",__func__, pdata->bp_id);
\r
471 bp_request_gpio(bp);
\r
475 wake_lock_init(&bp->bp_wakelock, WAKE_LOCK_SUSPEND, "bp_wakelock");
\r
476 if((bp->ops->bp_wakeup_ap) && (bp->ops->trig != BP_UNKNOW_DATA))
\r
478 irq = gpio_to_irq(bp->ops->bp_wakeup_ap);
\r
479 result = request_irq(irq, bp_wake_up_irq, bp->ops->trig, "bp_wakeup_ap", bp);
\r
481 printk("%s: request_irq(%d) failed\n", __func__, bp->ops->bp_wakeup_ap);
\r
482 gpio_free(pdata->bp_wakeup_ap);
\r
485 bp->ops->irq = irq;
\r
489 bp->status = BP_OFF;
\r
491 if(!bp->ops->private_miscdev)
\r
493 bp->fops.owner = THIS_MODULE;
\r
494 bp->fops.open = bp_dev_open;
\r
495 bp->fops.write = bp_dev_write;
\r
496 bp->fops.release = bp_dev_release;
\r
497 bp->fops.unlocked_ioctl = bp_dev_ioctl;
\r
499 bp->miscdev.minor = MISC_DYNAMIC_MINOR;
\r
500 if(bp->ops->misc_name)
\r
501 bp->miscdev.name = bp->ops->misc_name;
\r
503 bp->miscdev.name = BP_DEV_NAME;
\r
504 bp->miscdev.fops = &bp->fops;
\r
508 memcpy(&bp->miscdev, bp->ops->private_miscdev, sizeof(*bp->ops->private_miscdev));
\r
512 result = misc_register(&bp->miscdev);
\r
514 printk("misc_register err\n");
\r
518 bp->id_fops.owner = THIS_MODULE;
\r
519 bp->id_fops.open = bp_id_open;
\r
520 bp->id_fops.release = bp_id_release;
\r
521 bp->id_fops.unlocked_ioctl = bp_id_ioctl;
\r
523 bp->id_miscdev.minor = MISC_DYNAMIC_MINOR;
\r
524 bp->id_miscdev.name = "bp_id";
\r
525 bp->id_miscdev.fops = &bp->id_fops;
\r
526 result = misc_register(&bp->id_miscdev);
\r
528 printk("misc_register err\n");
\r
534 platform_set_drvdata(pdev, bp);
\r
536 printk("%s:init success\n",__func__);
\r
541 int bp_suspend(struct platform_device *pdev, pm_message_t state)
\r
543 struct bp_private_data *bp = platform_get_drvdata(pdev);
\r
545 if(bp->ops->suspend)
\r
546 bp->ops->suspend(bp);
\r
547 enable_irq_wake(bp->ops->irq);
\r
551 int bp_resume(struct platform_device *pdev)
\r
553 struct bp_private_data *bp = platform_get_drvdata(pdev);
\r
555 disable_irq_wake(bp->ops->irq);
\r
556 if(bp->ops->resume)
\r
557 bp->ops->resume(bp);
\r
562 void bp_shutdown(struct platform_device *pdev)
\r
564 struct bp_private_data *bp = platform_get_drvdata(pdev);
\r
566 if(bp->ops->shutdown)
\r
567 bp->ops->shutdown(bp);
\r
569 free_irq(bp->ops->irq,bp);
\r
574 int bp_register_slave(struct bp_private_data *bp,
\r
575 struct bp_platform_data *slave_pdata,
\r
576 struct bp_operate *(*get_bp_ops)(void))
\r
579 struct bp_operate *ops = get_bp_ops();
\r
580 if((ops->bp_id >= BP_ID_NUM) || (ops->bp_id <= BP_ID_INVALID))
\r
582 printk("%s:%s id is error %d\n", __func__, ops->name, ops->bp_id);
\r
585 g_bp_ops[ops->bp_id] = ops;
\r
586 printk("%s:%s,id=%d\n",__func__,g_bp_ops[ops->bp_id]->name, ops->bp_id);
\r
591 int bp_unregister_slave(struct bp_private_data *bp,
\r
592 struct bp_platform_data *slave_pdata,
\r
593 struct bp_operate *(*get_bp_ops)(void))
\r
596 struct bp_operate *ops = get_bp_ops();
\r
597 if((ops->bp_id >= BP_ID_NUM) || (ops->bp_id <= BP_ID_INVALID))
\r
599 printk("%s:%s id is error %d\n", __func__, ops->name, ops->bp_id);
\r
602 printk("%s:%s,id=%d\n",__func__,g_bp_ops[ops->bp_id]->name, ops->bp_id);
\r
603 g_bp_ops[ops->bp_id] = NULL;
\r
608 static struct platform_driver bp_driver = {
\r
610 .shutdown = bp_shutdown,
\r
611 .suspend = bp_suspend,
\r
612 .resume = bp_resume,
\r
615 .owner = THIS_MODULE,
\r
619 static int __init bp_init(void)
\r
622 //bp_class = class_create(THIS_MODULE, "bp-auto");
\r
623 //ret = class_create_file(bp_class, &class_attr_bp_status);
\r
626 // printk("Fail to create class bp-auto\n");
\r
628 return platform_driver_register(&bp_driver);
\r
631 static void __exit bp_exit(void)
\r
633 platform_driver_unregister(&bp_driver);
\r
634 //class_remove_file(bp_class, &class_attr_bp_status);
\r
637 module_init(bp_init);
\r
638 module_exit(bp_exit);
\r
640 MODULE_AUTHOR("ROCKCHIP Corporation:lw@rock-chips.com");
\r
641 MODULE_DESCRIPTION("device interface for auto modem driver");
\r
642 MODULE_LICENSE("GPL");
\r