2 * Copyright (C) 2010-2011 RDA Micro <anli@rdamicro.com>
\r
3 * This file belong to RDA micro
\r
4 * File: drivers/char/tcc_bt_dev.c
\r
7 #include <linux/kernel.h>
\r
8 #include <linux/module.h>
\r
9 #include <linux/fs.h>
\r
10 #include <asm/uaccess.h>
\r
11 #include <linux/ioctl.h>
\r
12 #include <linux/device.h>
\r
14 //#include <mach/bsp.h>
\r
16 #include <linux/delay.h>
\r
18 //#include <linux/tcc_bt_dev.h>
\r
19 //#include <mach/tcc_pca953x.h>
\r
21 #include <linux/gpio.h>
\r
22 #include <mach/gpio.h>
\r
23 #include <asm/mach-types.h>
\r
25 #include <mach/iomux.h>
\r
26 #include <linux/interrupt.h>
\r
27 #include <asm/irq.h>
\r
28 #include <linux/wakelock.h>
\r
38 #define LDO_ON_PIN RK2928_PIN3_PC0
\r
39 #define RDA_BT_HOST_WAKE_PIN RK2928_PIN0_PC5
\r
42 #define BT_DEV_OFF 0
\r
44 #define BT_DEV_MAJOR_NUM 234
\r
45 #define BT_DEV_MINOR_NUM 0
\r
47 //#define IOCTL_BT_DEV_POWER _IO(BT_DEV_MAJOR_NUM, 100)
\r
48 //#define IOCTL_BT_DEV_SPECIFIC _IO(BT_DEV_MAJOR_NUM, 101)
\r
49 //#define IOCTL_BT_DEV_IS_POWER _IO(BT_DEV_MAJOR_NUM, 102)
\r
52 #define IOCTL_BT_DEV_POWER _IO(BT_DEV_MAJOR_NUM, 100)
\r
53 #define IOCTL_BT_DEV_CTRL _IO(BT_DEV_MAJOR_NUM, 101)
\r
54 #define IOCTL_BT_SET_EINT _IO(BT_DEV_MAJOR_NUM, 102)
\r
55 #define IOCTL_BT_DEV_SPECIFIC _IO(BT_DEV_MAJOR_NUM, 103)
\r
58 static int bt_is_power = 0;
\r
59 static int rda_bt_irq = 0;
\r
60 static int irq_mask = 0;
\r
61 extern void export_bt_hci_wakeup_chip(void);
\r
63 #define DEV_NAME "tcc_bt_dev"
\r
64 static struct class *bt_dev_class;
\r
67 int module; // 0x12:CSR, 0x34:Broadcom
\r
72 static int tcc_bt_dev_open(struct inode *inode, struct file *file)
\r
74 printk("[## BT ##] tcc_bt_dev_open\n");
\r
78 static int tcc_bt_dev_release(struct inode *inode, struct file *file)
\r
80 printk("[## BT ##] tcc_bt_dev_release\n");
\r
84 static int tcc_bt_power_control(int on_off)
\r
86 // volatile PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);
\r
88 printk("[## BT ##] tcc_bt_power_control input[%d]\n", on_off);
\r
90 if(on_off == BT_DEV_ON)
\r
92 gpio_direction_output(LDO_ON_PIN, GPIO_HIGH);
\r
93 bt_is_power = on_off;
\r
96 else if(on_off == BT_DEV_OFF)
\r
98 gpio_direction_output(LDO_ON_PIN, GPIO_LOW);
\r
99 bt_is_power = BT_DEV_OFF;
\r
104 printk("[## BT_ERR ##] input_error On[%d] Off[%d]\n", BT_DEV_ON, BT_DEV_OFF);
\r
111 static int tcc_bt_get_info(tcc_bt_info_t* arg)
\r
113 tcc_bt_info_t *info_t;
\r
116 info_t = (tcc_bt_info_t *)arg;
\r
117 copy_from_user(info_t, (tcc_bt_info_t *)arg, sizeof(tcc_bt_info_t));
\r
121 printk("[## BT ##] module[0x%x]\n", module_t);
\r
123 info_t->module = module_t;
\r
125 copy_to_user((tcc_bt_info_t *)arg, info_t, sizeof(tcc_bt_info_t));
\r
130 static long tcc_bt_dev_ioctl(struct file *file, unsigned int cmd,unsigned long arg)
\r
132 void __user *argp = (void __user *)arg;
\r
136 //printk("[## BT ##] tcc_bt_dev_ioctl cmd[%d] arg[%d]\n", cmd, arg);
\r
139 case IOCTL_BT_DEV_POWER:
\r
140 if (copy_from_user(&rate, argp, sizeof(rate)))
\r
142 printk("[## BT ##] IOCTL_BT_DEV_POWER cmd[%d] parm1[%d]\n", cmd, rate);
\r
143 tcc_bt_power_control(rate);
\r
147 case IOCTL_BT_DEV_SPECIFIC:
\r
148 printk("[## BT ##] IOCTL_BT_DEV_SPECIFIC cmd[%d]\n", cmd);
\r
149 tcc_bt_get_info((tcc_bt_info_t*)arg);
\r
152 //case IOCTL_BT_DEV_IS_POWER:
\r
153 //if (copy_to_user(argp, &bt_is_power, sizeof(bt_is_power)))
\r
155 case IOCTL_BT_SET_EINT:
\r
156 printk("[## BT ##] IOCTL_BT_SET_EINT cmd[%d]\n", cmd);
\r
160 enable_irq(rda_bt_irq);
\r
164 printk("[## BT ##] tcc_bt_dev_ioctl cmd[%d]\n", cmd);
\r
172 struct file_operations tcc_bt_dev_ops = {
\r
173 .owner = THIS_MODULE,
\r
174 .unlocked_ioctl = tcc_bt_dev_ioctl,
\r
175 .open = tcc_bt_dev_open,
\r
176 .release = tcc_bt_dev_release,
\r
179 struct wake_lock rda_bt_wakelock;
\r
180 static irqreturn_t rda_5876_host_wake_irq(int irq, void *dev)
\r
182 printk("rda_5876_host_wake_irq\n");
\r
183 //export_bt_hci_wakeup_chip();
\r
184 wake_lock_timeout(&rda_bt_wakelock, 3 * HZ);
\r
185 disable_irq(rda_bt_irq);
\r
187 return IRQ_HANDLED;
\r
190 static int tcc_bt_init_module(void)
\r
194 wake_lock_init(&rda_bt_wakelock, WAKE_LOCK_SUSPEND, "rda_bt_wake");
\r
195 ret=gpio_request(LDO_ON_PIN, "ldoonpin");
\r
197 printk("%s:fail to request gpio %d\n",__func__,LDO_ON_PIN);
\r
200 gpio_set_value(LDO_ON_PIN, GPIO_LOW);//GPIO_LOW
\r
201 gpio_direction_output(LDO_ON_PIN, GPIO_LOW);//GPIO_LOW
\r
203 if(rda_bt_irq == 0){
\r
204 if(gpio_request(RDA_BT_HOST_WAKE_PIN, "bt_wake") != 0){
\r
205 printk("RDA_BT_HOST_WAKE_PIN request fail!\n");
\r
208 gpio_direction_input(RDA_BT_HOST_WAKE_PIN);
\r
210 rda_bt_irq = gpio_to_irq(RDA_BT_HOST_WAKE_PIN);
\r
211 ret = request_irq(rda_bt_irq, rda_5876_host_wake_irq, IRQF_TRIGGER_RISING, "bt_host_wake",NULL);
\r
213 printk("bt_host_wake irq request fail\n");
\r
215 gpio_free(RDA_BT_HOST_WAKE_PIN);
\r
218 enable_irq_wake(rda_bt_irq); //bt irq can wakeup host when host sleep
\r
219 disable_irq(rda_bt_irq);
\r
221 printk("request_irq bt_host_wake\n");
\r
225 printk("[## BT ##] init_module\n");
\r
226 ret = register_chrdev(BT_DEV_MAJOR_NUM, DEV_NAME, &tcc_bt_dev_ops);
\r
228 bt_dev_class = class_create(THIS_MODULE, DEV_NAME);
\r
229 device_create(bt_dev_class, NULL, MKDEV(BT_DEV_MAJOR_NUM, BT_DEV_MINOR_NUM), NULL, DEV_NAME);
\r
231 if(machine_is_tcc8900()){
\r
232 gpio_request(TCC_GPB(25), "bt_power");
\r
233 gpio_request(TCC_GPEXT2(9), "bt_reset");
\r
234 gpio_direction_output(TCC_GPB(25), 0); // output
\r
235 gpio_direction_output(TCC_GPEXT2(9), 0);
\r
236 }else if(machine_is_tcc9300() || machine_is_tcc8800()) { // #elif defined (CONFIG_MACH_TCC9300)
\r
237 //gpio_set_value(TCC_GPEXT1(7), 0); /* BT-ON Disable */
\r
238 gpio_request(TCC_GPEXT3(2), "bt_wake");
\r
239 gpio_request(TCC_GPEXT2(4), "bt_reset");
\r
240 gpio_direction_output(TCC_GPEXT3(2), 0); // output
\r
241 gpio_direction_output(TCC_GPEXT2(4), 0);
\r
243 else if(machine_is_m801_88())
\r
245 gpio_request(TCC_GPA(13), "bt_reset");
\r
246 gpio_request(TCC_GPB(22), "BT WAKE");
\r
247 gpio_direction_output(TCC_GPA(13), 0); // output
\r
248 gpio_direction_output(TCC_GPB(22), 0); // output
\r
252 printk("[## BT ##] [%d]fail to register the character device\n", ret);
\r
259 static void tcc_bt_cleanup_module(void)
\r
261 printk("[## BT ##] cleanup_module\n");
\r
262 unregister_chrdev(BT_DEV_MAJOR_NUM, DEV_NAME);
\r
263 wake_lock_destroy(&rda_bt_wakelock);
\r
267 late_initcall(tcc_bt_init_module);
\r
268 module_exit(tcc_bt_cleanup_module);
\r
271 MODULE_AUTHOR("Telechips Inc. linux@telechips.com");
\r
272 MODULE_DESCRIPTION("TCC_BT_DEV");
\r
273 MODULE_LICENSE("GPL");
\r