--- /dev/null
+/*\r
+ * Copyright (C) 2010-2011 RDA Micro <anli@rdamicro.com>\r
+ * This file belong to RDA micro\r
+ * File: drivers/char/tcc_bt_dev.c\r
+ */\r
+\r
+#include <linux/kernel.h>\r
+#include <linux/module.h>\r
+#include <linux/fs.h>\r
+#include <asm/uaccess.h>\r
+#include <linux/ioctl.h>\r
+#include <linux/device.h>\r
+\r
+//#include <mach/bsp.h>\r
+#include <asm/io.h>\r
+#include <linux/delay.h>\r
+\r
+//#include <linux/tcc_bt_dev.h>\r
+//#include <mach/tcc_pca953x.h>\r
+\r
+#include <linux/gpio.h>\r
+#include <mach/gpio.h>\r
+#include <asm/mach-types.h>\r
+\r
+#include <mach/iomux.h>\r
+#include <linux/interrupt.h>\r
+#include <asm/irq.h>\r
+#include <linux/wakelock.h>\r
+\r
+#ifndef ON\r
+#define ON 1\r
+#endif\r
+\r
+#ifndef OFF\r
+#define OFF 0\r
+#endif\r
+\r
+#define LDO_ON_PIN RK2928_PIN3_PC0\r
+#define RDA_BT_HOST_WAKE_PIN RK2928_PIN0_PC5\r
+\r
+#define BT_DEV_ON 1\r
+#define BT_DEV_OFF 0\r
+\r
+#define BT_DEV_MAJOR_NUM 234\r
+#define BT_DEV_MINOR_NUM 0\r
+\r
+//#define IOCTL_BT_DEV_POWER _IO(BT_DEV_MAJOR_NUM, 100)\r
+//#define IOCTL_BT_DEV_SPECIFIC _IO(BT_DEV_MAJOR_NUM, 101)\r
+//#define IOCTL_BT_DEV_IS_POWER _IO(BT_DEV_MAJOR_NUM, 102)\r
+\r
+\r
+#define IOCTL_BT_DEV_POWER _IO(BT_DEV_MAJOR_NUM, 100)\r
+#define IOCTL_BT_DEV_CTRL _IO(BT_DEV_MAJOR_NUM, 101)\r
+#define IOCTL_BT_SET_EINT _IO(BT_DEV_MAJOR_NUM, 102)\r
+#define IOCTL_BT_DEV_SPECIFIC _IO(BT_DEV_MAJOR_NUM, 103)\r
+\r
+\r
+static int bt_is_power = 0;\r
+static int rda_bt_irq = 0;\r
+static int irq_mask = 0;\r
+extern void export_bt_hci_wakeup_chip(void);\r
+\r
+#define DEV_NAME "tcc_bt_dev"\r
+static struct class *bt_dev_class;\r
+\r
+typedef struct {\r
+ int module; // 0x12:CSR, 0x34:Broadcom\r
+ int TMP1;\r
+ int TMP2;\r
+} tcc_bt_info_t;\r
+\r
+static int tcc_bt_dev_open(struct inode *inode, struct file *file)\r
+{\r
+ printk("[## BT ##] tcc_bt_dev_open\n");\r
+ return 0;\r
+}\r
+\r
+static int tcc_bt_dev_release(struct inode *inode, struct file *file)\r
+{\r
+ printk("[## BT ##] tcc_bt_dev_release\n");\r
+ return 0;\r
+}\r
+\r
+int tcc_bt_power_control(int on_off)\r
+{\r
+// volatile PGPIO pGPIO = (volatile PGPIO)tcc_p2v(HwGPIO_BASE);\r
+ \r
+ printk("[## BT ##] tcc_bt_power_control input[%d]\n", on_off);\r
+ \r
+ if(on_off == BT_DEV_ON)\r
+ { \r
+ gpio_direction_output(LDO_ON_PIN, GPIO_HIGH);\r
+ bt_is_power = on_off;\r
+ msleep(500);\r
+ }\r
+ else if(on_off == BT_DEV_OFF)\r
+ {\r
+ gpio_direction_output(LDO_ON_PIN, GPIO_LOW);\r
+ bt_is_power = BT_DEV_OFF;\r
+ msleep(500);\r
+ }\r
+ else\r
+ {\r
+ printk("[## BT_ERR ##] input_error On[%d] Off[%d]\n", BT_DEV_ON, BT_DEV_OFF);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static int tcc_bt_get_info(tcc_bt_info_t* arg)\r
+{\r
+ tcc_bt_info_t *info_t;\r
+ int module_t;\r
+ \r
+ info_t = (tcc_bt_info_t *)arg;\r
+ copy_from_user(info_t, (tcc_bt_info_t *)arg, sizeof(tcc_bt_info_t));\r
+\r
+ module_t = 0x56; \r
+\r
+ printk("[## BT ##] module[0x%x]\n", module_t);\r
+\r
+ info_t->module = module_t;\r
+\r
+ copy_to_user((tcc_bt_info_t *)arg, info_t, sizeof(tcc_bt_info_t));\r
+\r
+ return 0;\r
+}\r
+\r
+static long tcc_bt_dev_ioctl(struct file *file, unsigned int cmd,unsigned long arg)\r
+{\r
+ void __user *argp = (void __user *)arg;\r
+ char msg[14];\r
+ int ret = -1;\r
+ char rate;\r
+ //printk("[## BT ##] tcc_bt_dev_ioctl cmd[%d] arg[%d]\n", cmd, arg);\r
+ switch(cmd)\r
+ {\r
+ case IOCTL_BT_DEV_POWER: \r
+ if (copy_from_user(&rate, argp, sizeof(rate)))\r
+ return -EFAULT;\r
+ printk("[## BT ##] IOCTL_BT_DEV_POWER cmd[%d] parm1[%d]\n", cmd, rate);\r
+ tcc_bt_power_control(rate);\r
+ // GPIO Control\r
+ break;\r
+ \r
+ case IOCTL_BT_DEV_SPECIFIC:\r
+ printk("[## BT ##] IOCTL_BT_DEV_SPECIFIC cmd[%d]\n", cmd);\r
+ tcc_bt_get_info((tcc_bt_info_t*)arg);\r
+ break;\r
+\r
+ //case IOCTL_BT_DEV_IS_POWER:\r
+ //if (copy_to_user(argp, &bt_is_power, sizeof(bt_is_power)))\r
+ //return -EFAULT;\r
+ case IOCTL_BT_SET_EINT:\r
+ printk("[## BT ##] IOCTL_BT_SET_EINT cmd[%d]\n", cmd);\r
+ if (irq_mask)\r
+ {\r
+ irq_mask = 0;\r
+ enable_irq(rda_bt_irq);\r
+ }\r
+ break;\r
+ default :\r
+ printk("[## BT ##] tcc_bt_dev_ioctl cmd[%d]\n", cmd);\r
+ break;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+struct file_operations tcc_bt_dev_ops = {\r
+ .owner = THIS_MODULE,\r
+ .unlocked_ioctl = tcc_bt_dev_ioctl,\r
+ .open = tcc_bt_dev_open,\r
+ .release = tcc_bt_dev_release,\r
+};\r
+\r
+struct wake_lock rda_bt_wakelock;\r
+static irqreturn_t rda_5876_host_wake_irq(int irq, void *dev)\r
+{\r
+ printk("rda_5876_host_wake_irq\n");\r
+ //export_bt_hci_wakeup_chip();\r
+ wake_lock_timeout(&rda_bt_wakelock, 3 * HZ); \r
+ disable_irq(rda_bt_irq);\r
+ irq_mask = 1; \r
+ return IRQ_HANDLED;\r
+}\r
+\r
+int init_module(void)\r
+{\r
+ int ret;\r
+\r
+ wake_lock_init(&rda_bt_wakelock, WAKE_LOCK_SUSPEND, "rda_bt_wake");\r
+ ret=gpio_request(LDO_ON_PIN, "ldoonpin");\r
+ if(ret < 0) {\r
+ printk("%s:fail to request gpio %d\n",__func__,LDO_ON_PIN);\r
+ return ret;\r
+ }\r
+ gpio_set_value(LDO_ON_PIN, GPIO_LOW);//GPIO_LOW\r
+ gpio_direction_output(LDO_ON_PIN, GPIO_LOW);//GPIO_LOW\r
+\r
+ if(rda_bt_irq == 0){\r
+ if(gpio_request(RDA_BT_HOST_WAKE_PIN, "bt_wake") != 0){\r
+ printk("RDA_BT_HOST_WAKE_PIN request fail!\n");\r
+ return -EIO;\r
+ }\r
+ gpio_direction_input(RDA_BT_HOST_WAKE_PIN);\r
+\r
+ rda_bt_irq = gpio_to_irq(RDA_BT_HOST_WAKE_PIN);\r
+ ret = request_irq(rda_bt_irq, rda_5876_host_wake_irq, IRQF_TRIGGER_RISING, "bt_host_wake",NULL);\r
+ if(ret){\r
+ printk("bt_host_wake irq request fail\n");\r
+ rda_bt_irq = 0;\r
+ gpio_free(RDA_BT_HOST_WAKE_PIN);\r
+ return -EIO;\r
+ }\r
+ enable_irq_wake(rda_bt_irq); //bt irq can wakeup host when host sleep\r
+ disable_irq(rda_bt_irq);\r
+ irq_mask = 1;\r
+ printk("request_irq bt_host_wake\n");\r
+ }\r
+\r
+ \r
+ printk("[## BT ##] init_module\n");\r
+ ret = register_chrdev(BT_DEV_MAJOR_NUM, DEV_NAME, &tcc_bt_dev_ops);\r
+\r
+ bt_dev_class = class_create(THIS_MODULE, DEV_NAME);\r
+ device_create(bt_dev_class, NULL, MKDEV(BT_DEV_MAJOR_NUM, BT_DEV_MINOR_NUM), NULL, DEV_NAME);\r
+#if 0\r
+ if(machine_is_tcc8900()){\r
+ gpio_request(TCC_GPB(25), "bt_power");\r
+ gpio_request(TCC_GPEXT2(9), "bt_reset");\r
+ gpio_direction_output(TCC_GPB(25), 0); // output\r
+ gpio_direction_output(TCC_GPEXT2(9), 0);\r
+ }else if(machine_is_tcc9300() || machine_is_tcc8800()) { // #elif defined (CONFIG_MACH_TCC9300)\r
+ //gpio_set_value(TCC_GPEXT1(7), 0); /* BT-ON Disable */\r
+ gpio_request(TCC_GPEXT3(2), "bt_wake");\r
+ gpio_request(TCC_GPEXT2(4), "bt_reset");\r
+ gpio_direction_output(TCC_GPEXT3(2), 0); // output\r
+ gpio_direction_output(TCC_GPEXT2(4), 0);\r
+ }\r
+ else if(machine_is_m801_88())\r
+ {\r
+ gpio_request(TCC_GPA(13), "bt_reset");\r
+ gpio_request(TCC_GPB(22), "BT WAKE");\r
+ gpio_direction_output(TCC_GPA(13), 0); // output\r
+ gpio_direction_output(TCC_GPB(22), 0); // output\r
+ }\r
+#endif \r
+ if(ret < 0){\r
+ printk("[## BT ##] [%d]fail to register the character device\n", ret);\r
+ return ret;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+void cleanup_module(void)\r
+{\r
+ printk("[## BT ##] cleanup_module\n");\r
+ unregister_chrdev(BT_DEV_MAJOR_NUM, DEV_NAME);\r
+ wake_lock_destroy(&rda_bt_wakelock);\r
+}\r
+\r
+\r
+late_initcall(init_module);\r
+module_exit(cleanup_module);\r
+\r
+\r
+MODULE_AUTHOR("Telechips Inc. linux@telechips.com");\r
+MODULE_DESCRIPTION("TCC_BT_DEV");\r
+MODULE_LICENSE("GPL");\r
+\r
+\r