BT: add bluetooth bcm4329 driver
author陈智 <cz@rock-chips.com>
Mon, 20 Dec 2010 13:45:12 +0000 (21:45 +0800)
committer陈智 <cz@rock-chips.com>
Mon, 20 Dec 2010 13:45:12 +0000 (21:45 +0800)
arch/arm/configs/rk29_sdk_defconfig
arch/arm/mach-rk29/Makefile [changed mode: 0644->0755]
arch/arm/mach-rk29/board-rk29sdk-rfkill.c [new file with mode: 0755]
arch/arm/mach-rk29/board-rk29sdk.c
drivers/serial/rk29_serial.c [changed mode: 0644->0755]
net/bluetooth/rfcomm/core.c [changed mode: 0644->0755]

index 540c54a40fd47cea30a054061d6e6d2492dea334..839a760cbc0a8a93f2a36b87076bdd52b7959d87 100755 (executable)
@@ -197,7 +197,7 @@ CONFIG_MMU=y
 CONFIG_ARCH_RK29=y
 CONFIG_WIFI_CONTROL_FUNC=y
 CONFIG_MACH_RK29SDK=y
-CONFIG_RK29_MEM_SIZE_M=512
+CONFIG_MACH_RK29SDK_MEM_SIZE_M=512
 
 #
 # RK29 VPU (Video Processing Unit) support
@@ -1652,27 +1652,7 @@ CONFIG_CRAMFS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_V4_1=y
-CONFIG_ROOT_NFS=y
-# CONFIG_NFSD is not set
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_ACL_SUPPORT=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=y
-CONFIG_RPCSEC_GSS_KRB5=y
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
 
 #
 # Partition Types
old mode 100644 (file)
new mode 100755 (executable)
index 1ed0be1..4ebbd8f
@@ -1,4 +1,4 @@
 obj-y += timer.o io.o devices.o iomux.o clock.o rk29-pl330.o dma.o gpio.o
 obj-$(CONFIG_RK29_VPU) += vpu.o vpu_mem.o
-obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o board-rk29sdk-key.o
+obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o board-rk29sdk-key.o board-rk29sdk-rfkill.o
 obj-$(CONFIG_MACH_RK29WINACCORD) += board-rk29-winaccord.o board-rk29sdk-key.o
diff --git a/arch/arm/mach-rk29/board-rk29sdk-rfkill.c b/arch/arm/mach-rk29/board-rk29sdk-rfkill.c
new file mode 100755 (executable)
index 0000000..604ea9f
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ * Author: roger_chen <cz@rock-chips.com>
+ *
+ * This program is the bluetooth device bcm4329's driver,
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rfkill.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wakelock.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <mach/gpio.h>
+#include <asm/irq.h>
+#include <mach/iomux.h>
+#include <linux/wakelock.h>
+#include <linux/timer.h>
+
+#if 0
+#define DBG(x...)   printk(KERN_INFO x)
+#else
+#define DBG(x...)
+#endif
+
+#define BT_WAKE_HOST_SUPPORT 0
+
+struct bt_ctrl
+{
+    struct rfkill *bt_rfk;
+#if BT_WAKE_HOST_SUPPORT
+    struct timer_list tl;
+    bool b_HostWake;
+    struct wake_lock bt_wakelock;
+#endif
+};
+
+#define BT_GPIO_POWER           RK29_PIN5_PD6
+#define IOMUX_BT_GPIO_POWER     rk29_mux_api_set(GPIO5D6_SDMMC1PWREN_NAME, GPIO5H_GPIO5D6);
+#define BT_GPIO_RESET                  RK29_PIN6_PC4
+#define BT_GPIO_WAKE_UP         RK29_PIN6_PC5
+#define BT_GPIO_WAKE_UP_HOST    //RK2818_PIN_PA7
+#define IOMUX_BT_GPIO_WAKE_UP_HOST() //rk2818_mux_api_set(GPIOA7_FLASHCS3_SEL_NAME,0);
+
+#define BT_WAKE_LOCK_TIMEOUT    10 //s
+
+static const char bt_name[] = "bcm4329";
+extern int rk29sdk_bt_power_state;
+extern int rk29sdk_wifi_power_state;
+
+struct bt_ctrl gBtCtrl;
+    
+#if BT_WAKE_HOST_SUPPORT
+void resetBtHostSleepTimer(void)
+{
+    mod_timer(&(gBtCtrl.tl),jiffies + BT_WAKE_LOCK_TIMEOUT*HZ);//ÔÙÖØÐÂÉèÖó¬Ê±Öµ¡£    
+}
+
+void btWakeupHostLock(void)
+{
+    if(gBtCtrl.b_HostWake == false){
+        DBG("*************************Lock\n");
+        wake_lock(&(gBtCtrl.bt_wakelock));
+        gBtCtrl.b_HostWake = true;
+    }
+}
+
+void btWakeupHostUnlock(void)
+{
+    if(gBtCtrl.b_HostWake == true){        
+        DBG("*************************UnLock\n");
+        wake_unlock(&(gBtCtrl.bt_wakelock));  //ÈÃϵͳ˯Ãß    
+        gBtCtrl.b_HostWake = false;
+    }    
+}
+
+static void timer_hostSleep(unsigned long arg)
+{     
+       DBG("%s---b_HostWake=%d\n",__FUNCTION__,gBtCtrl.b_HostWake);
+    btWakeupHostUnlock();
+}
+
+
+#ifdef CONFIG_PM
+static int bcm4329_rfkill_suspend(struct platform_device *pdev, pm_message_t state)
+{   
+    DBG("%s\n",__FUNCTION__);          
+    return 0;
+}
+
+static int bcm4329_rfkill_resume(struct platform_device *pdev)
+{  
+    DBG("%s\n",__FUNCTION__);     
+    btWakeupHostLock();
+    resetBtHostSleepTimer();
+    return 0;
+}
+#else
+#define bcm4329_rfkill_suspend NULL
+#define bcm4329_rfkill_resume  NULL
+#endif
+
+static irqreturn_t bcm4329_wake_host_irq(int irq, void *dev)
+{
+    btWakeupHostLock();
+    resetBtHostSleepTimer();
+       return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_BT_HCIBCM4325
+int bcm4325_sleep(int bSleep)
+{
+//     printk("*************bt enter sleep***************\n");
+    if (bSleep)
+    gpio_set_value(BT_GPIO_WAKE_UP, GPIO_LOW);   //low represent bt device may enter sleep  
+    else
+    gpio_set_value(BT_GPIO_WAKE_UP, GPIO_HIGH);  //high represent bt device must be awake 
+
+       //printk("sleep=%d\n",bSleep);
+}
+#endif
+  
+static int bcm4329_set_block(void *data, bool blocked)
+{
+       DBG("%s---blocked :%d\n", __FUNCTION__, blocked);
+
+        IOMUX_BT_GPIO_POWER;
+
+       if (false == blocked) { 
+                       gpio_set_value(BT_GPIO_POWER, GPIO_HIGH);  /* bt power on */
+               gpio_set_value(BT_GPIO_RESET, GPIO_HIGH);  /* bt reset deactive*/
+               mdelay(20);
+        
+#if BT_WAKE_HOST_SUPPORT     
+            btWakeupHostLock();
+#endif         
+               pr_info("bt turn on power\n");
+       }
+       else {
+#if BT_WAKE_HOST_SUPPORT     
+            btWakeupHostUnlock();
+#endif
+               if (!rk29sdk_wifi_power_state) {
+                       gpio_set_value(BT_GPIO_POWER, GPIO_LOW);  /* bt power off */
+               mdelay(20);     
+               pr_info("bt shut off power\n");
+               }else {
+                       pr_info("bt shouldn't shut off power, wifi is using it!\n");
+               }
+
+               gpio_set_value(BT_GPIO_RESET, GPIO_LOW);  /* bt reset active*/
+               mdelay(20);
+       }
+
+       rk29sdk_bt_power_state = !blocked;
+       return 0;
+}
+
+
+static const struct rfkill_ops bcm4329_rfk_ops = {
+       .set_block = bcm4329_set_block,
+};
+
+static int __init bcm4329_rfkill_probe(struct platform_device *pdev)
+{
+       int rc = 0;
+       bool default_state = true;
+       
+       DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
+       
+       /* default to bluetooth off */
+       bcm4329_set_block(NULL, default_state); /* blocked -> bt off */
+        
+       gBtCtrl.bt_rfk = rfkill_alloc(bt_name, 
+                NULL, 
+                RFKILL_TYPE_BLUETOOTH, 
+                &bcm4329_rfk_ops, 
+                NULL);
+
+       if (!gBtCtrl.bt_rfk)
+       {
+               printk("fail to rfkill_allocate************\n");
+               return -ENOMEM;
+       }
+       
+       rfkill_set_states(gBtCtrl.bt_rfk, default_state, false);
+
+       rc = rfkill_register(gBtCtrl.bt_rfk);
+       if (rc)
+       {
+               printk("failed to rfkill_register,rc=0x%x\n",rc);
+               rfkill_destroy(gBtCtrl.bt_rfk);
+       }
+       
+       gpio_request(BT_GPIO_POWER, NULL);
+       gpio_request(BT_GPIO_RESET, NULL);
+       gpio_request(BT_GPIO_WAKE_UP, NULL);
+
+#if BT_WAKE_HOST_SUPPORT
+    init_timer(&(gBtCtrl.tl));
+    gBtCtrl.tl.expires = jiffies + BT_WAKE_LOCK_TIMEOUT*HZ;        
+    gBtCtrl.tl.function = timer_hostSleep;        
+    add_timer(&(gBtCtrl.tl));
+    gBtCtrl.b_HostWake = false;
+    
+       wake_lock_init(&(gBtCtrl.bt_wakelock), WAKE_LOCK_SUSPEND, "bt_wake");
+       
+       rc = gpio_request(BT_GPIO_WAKE_UP_HOST, "bt_wake");
+       if (rc) {
+               printk("%s:failed to request RAHO_BT_WAKE_UP_HOST\n",__FUNCTION__);
+       }
+       
+       IOMUX_BT_GPIO_WAKE_UP_HOST();
+       gpio_pull_updown(BT_GPIO_WAKE_UP_HOST,GPIOPullUp);
+       rc = request_irq(gpio_to_irq(BT_GPIO_WAKE_UP_HOST),bcm4329_wake_host_irq,IRQF_TRIGGER_FALLING,NULL,NULL);
+       if(rc)
+       {
+               printk("%s:failed to request RAHO_BT_WAKE_UP_HOST irq\n",__FUNCTION__);
+               gpio_free(BT_GPIO_WAKE_UP_HOST);
+       }
+       enable_irq_wake(gpio_to_irq(BT_GPIO_WAKE_UP_HOST)); // so RAHO_BT_WAKE_UP_HOST can wake up system
+
+       printk(KERN_INFO "bcm4329 module has been initialized,rc=0x%x\n",rc);
+ #endif
+       return rc;
+
+       
+}
+
+
+static int __devexit bcm4329_rfkill_remove(struct platform_device *pdev)
+{
+       if (gBtCtrl.bt_rfk)
+               rfkill_unregister(gBtCtrl.bt_rfk);
+       gBtCtrl.bt_rfk = NULL;
+#if BT_WAKE_HOST_SUPPORT       
+    del_timer(&(gBtCtrl.tl));//ɾµô¶¨Ê±Æ÷
+    btWakeupHostUnlock();
+    wake_lock_destroy(&(gBtCtrl.bt_wakelock));
+#endif    
+       platform_set_drvdata(pdev, NULL);
+
+       DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
+       return 0;
+}
+
+static struct platform_driver bcm4329_rfkill_driver = {
+       .probe = bcm4329_rfkill_probe,
+       .remove = __devexit_p(bcm4329_rfkill_remove),
+       .driver = {
+               .name = "rk29sdk_rfkill", 
+               .owner = THIS_MODULE,
+       },      
+#if BT_WAKE_HOST_SUPPORT
+    .suspend = bcm4329_rfkill_suspend,
+    .resume = bcm4329_rfkill_resume,
+#endif
+};
+
+/*
+ * Module initialization
+ */
+static int __init bcm4329_mod_init(void)
+{
+       int ret;
+       DBG("Enter::%s,line=%d\n",__FUNCTION__,__LINE__);
+       ret = platform_driver_register(&bcm4329_rfkill_driver);
+       printk("ret=0x%x\n", ret);
+       return ret;
+}
+
+static void __exit bcm4329_mod_exit(void)
+{
+       platform_driver_unregister(&bcm4329_rfkill_driver);
+}
+
+module_init(bcm4329_mod_init);
+module_exit(bcm4329_mod_exit);
+MODULE_DESCRIPTION("bcm4329 Bluetooth driver");
+MODULE_AUTHOR("roger_chen cz@rock-chips.com");
+MODULE_LICENSE("GPL");
+
index 50cb23ac20c5e1e037034c96ae0de4abda1af27f..75d110c50949a5852863c10d2270e57721c81c53 100755 (executable)
@@ -1041,6 +1041,14 @@ static struct platform_device rk29sdk_wifi_device = {
 };
 #endif
 
+
+/* bluetooth rfkill device */
+static struct platform_device rk29sdk_rfkill = {
+        .name = "rk29sdk_rfkill",
+        .id = -1,
+};
+
+
 #ifdef CONFIG_VIVANTE
 static struct resource resources_gpu[] = {
     [0] = {
@@ -1141,6 +1149,13 @@ static struct platform_device *devices[] __initdata = {
 #ifdef CONFIG_UART1_RK29
        &rk29_device_uart1,
 #endif
+#ifdef CONFIG_UART0_RK29
+       &rk29_device_uart0,
+#endif
+#ifdef CONFIG_UART2_RK29
+       &rk29_device_uart2,
+#endif
+
 #ifdef CONFIG_SPIM0_RK29
     &rk29xx_device_spi0m,
 #endif
@@ -1187,6 +1202,11 @@ static struct platform_device *devices[] __initdata = {
 #ifdef CONFIG_WIFI_CONTROL_FUNC
         &rk29sdk_wifi_device,
 #endif
+
+#ifdef CONFIG_BT
+        &rk29sdk_rfkill,
+#endif
+
 #ifdef CONFIG_MTD_NAND_RK29
        &rk29_device_nand,
 #endif
old mode 100644 (file)
new mode 100755 (executable)
index 72bbe36..bd1fe6b
 #include <mach/board.h>
 #include "rk2818_serial.h"
 
+#define DBG_PORT    0
+#if 0
+#define DBG     printk
+#else
+#define DBG
+#endif
 /*
  * We wrap our port structure around the generic uart_port.
  */
@@ -174,6 +180,11 @@ static void rk29_serial_stop_tx(struct uart_port *port)
 static void rk29_serial_start_tx(struct uart_port *port)
 {
        struct circ_buf *xmit = &port->state->xmit;
+
+    if(DBG_PORT == port->line) {
+        DBG("TX:");
+    }
+    
        while(!(uart_circ_empty(xmit)))
        {
                while (!(rk29_uart_read(port,UART_USR) & UART_TRANSMIT_FIFO_NOT_FULL)){
@@ -181,6 +192,11 @@ static void rk29_serial_start_tx(struct uart_port *port)
             return;
         }
         rk29_uart_write(port,xmit->buf[xmit->tail],UART_THR);
+        
+        if(DBG_PORT == port->line) {
+            DBG("0x%x, ", xmit->buf[xmit->tail]);
+        }
+        
                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
                port->icount.tx++;
        }
@@ -188,6 +204,10 @@ static void rk29_serial_start_tx(struct uart_port *port)
                rk29_uart_write(port,UART_IER_RECV_DATA_AVAIL_INT_ENABLE,UART_IER);
        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
                uart_write_wakeup(port);        
+    
+    if(DBG_PORT == port->line) {
+        DBG("\n");
+    }
 }
 
 /*
@@ -221,6 +241,11 @@ static void rk29_serial_break_ctl(struct uart_port *port, int break_state)
 static void rk29_rx_chars(struct uart_port *port)
 {
        unsigned int ch, flag;
+    
+    if(DBG_PORT == port->line) {
+        DBG("RX:");
+    }
+    
        while((rk29_uart_read(port,UART_USR) & UART_RECEIVE_FIFO_NOT_EMPTY) == UART_RECEIVE_FIFO_NOT_EMPTY)
        {
                u32 lsr = rk29_uart_read(port, UART_LSR);
@@ -237,9 +262,16 @@ static void rk29_rx_chars(struct uart_port *port)
                        continue;
                } 
                uart_insert_char(port, 0, 0, ch, flag);
+        
+        if(DBG_PORT == port->line) {
+            DBG("0x%x, ", ch);
+        }
        }
        tty_flip_buffer_push(port->state->port.tty);
-       
+
+    if(DBG_PORT == port->line) {
+        DBG("\n");
+    }
 }
 
 /*
@@ -277,7 +309,20 @@ static int rk29_serial_startup(struct uart_port *port)
        struct rk29_port *rk29_port = UART_TO_RK29(port);
        struct tty_struct *tty = port->state->port.tty; 
        int retval;     
-               
+
+    if(2 == port->line) {
+        rk29_mux_api_set(GPIO2B1_UART2SOUT_NAME, GPIO2L_UART2_SOUT);
+        rk29_mux_api_set(GPIO2B0_UART2SIN_NAME, GPIO2L_UART2_SIN);
+        rk29_mux_api_set(GPIO2A7_UART2RTSN_NAME, GPIO2L_UART2_RTS_N);
+        rk29_mux_api_set(GPIO2A6_UART2CTSN_NAME, GPIO2L_UART2_CTS_N);
+    }
+    else if(0 == port->line) {
+        rk29_mux_api_set(GPIO1B7_UART0SOUT_NAME, GPIO1L_UART0_SOUT);
+        rk29_mux_api_set(GPIO1B6_UART0SIN_NAME, GPIO1L_UART0_SIN);
+        rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N);
+        rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_UART0_CTS_N);
+    }
+    
        retval = request_irq(port->irq,rk29_uart_interrupt,IRQF_SHARED,
                     tty ? tty->name : "rk29_serial",port);
        if(retval)
old mode 100644 (file)
new mode 100755 (executable)
index c2e4333..b3dd3f0
@@ -243,7 +243,7 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d)
        return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level,
                                                                auth_type);
 }
-
+#if 0  //cz@rock-chips.com
 static void rfcomm_session_timeout(unsigned long arg)
 {
        struct rfcomm_session *s = (void *) arg;
@@ -269,7 +269,7 @@ static void rfcomm_session_clear_timer(struct rfcomm_session *s)
        if (timer_pending(&s->timer) && del_timer(&s->timer))
                rfcomm_session_put(s);
 }
-
+#endif
 /* ---- RFCOMM DLCs ---- */
 static void rfcomm_dlc_timeout(unsigned long arg)
 {
@@ -1891,14 +1891,14 @@ static inline void rfcomm_process_sessions(void)
        list_for_each_safe(p, n, &session_list) {
                struct rfcomm_session *s;
                s = list_entry(p, struct rfcomm_session, list);
-
+#if 0   //cz@rock-chips.com
                if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
                        s->state = BT_DISCONN;
                        rfcomm_send_disc(s, 0);
                        rfcomm_session_put(s);
                        continue;
                }
-
+#endif
                if (s->state == BT_LISTEN) {
                        rfcomm_accept_connection(s);
                        continue;