phonepad: add rda5990 bt\wifi support
authorlinjh <linjh@rock-chips.com>
Thu, 27 Sep 2012 09:57:40 +0000 (17:57 +0800)
committerlinjh <linjh@rock-chips.com>
Thu, 27 Sep 2012 10:04:00 +0000 (18:04 +0800)
[reference file]

modified:
arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c
drivers/bluetooth/hci_ldisc.c
drivers/mmc/host/rk29_sdmmc.c
net/bluetooth/hci_core.c

arch/arm/mach-rk2928/board-rk2928-sdk-sdmmc.c
drivers/bluetooth/hci_ldisc.c
drivers/mmc/host/rk29_sdmmc.c
net/bluetooth/hci_core.c

index d48e0c464e2a8dcadfeb7c91294a94194d7861d6..ba5a9e900998687f9ff6e8e218408e0d64d00482 100755 (executable)
@@ -224,6 +224,13 @@ static void rk29_sdmmc_set_iomux(int device_id, unsigned int bus_width)
 #define RK30SDK_WIFI_GPIO_RESET_ENABLE_VALUE GPIO_HIGH 
 #endif
 
+#if defined(CONFIG_RDA5990)
+#define RK30SDK_WIFI_GPIO_POWER_N       RK2928_PIN0_PD6
+#define RK30SDK_WIFI_GPIO_POWER_ENABLE_VALUE GPIO_HIGH 
+#define RK30SDK_WIFI_GPIO_RESET_N       RK2928_PIN3_PC2
+#define RK30SDK_WIFI_GPIO_RESET_ENABLE_VALUE GPIO_HIGH 
+#endif
+
 #define PREALLOC_WLAN_SEC_NUM           4
 #define PREALLOC_WLAN_BUF_NUM           160
 #define PREALLOC_WLAN_SECTION_HEADER    24
index 2c548724154c54b90aef23def0cea2e3c6eeca39..7fcaa47ed8a9971145c0d9ed07e1748ec31bfda9 100755 (executable)
 
 #define VERSION "2.2"
 
+#ifndef RDA_BT_SUPPORT
+#define RDA_BT_SUPPORT
+#endif
+
 static int reset = 0;
 
 static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
@@ -106,10 +110,44 @@ static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
        }
 }
 
+#ifdef RDA_BT_SUPPORT
+typedef enum
+{
+    HOST_WAKEUP_BT = 1,
+    BT_WAKEUP_HOST,
+    BT_SEND_WAKEUP
+}bt_wakeup_status;
+
+//extern atomic_t        need_wakeup_bt;
+extern volatile int need_wakeup_bt;
+EXPORT_SYMBOL(hci_uart_tx_wakeup);
+#endif
+
 static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
 {
        struct sk_buff *skb = hu->tx_skb;
 
+#ifdef RDA_BT_SUPPORT
+    //if(atomic_read(&need_wakeup_bt) == HOST_WAKEUP_BT 
+      // || atomic_read(&need_wakeup_bt) == BT_WAKEUP_HOST)
+    if(need_wakeup_bt == HOST_WAKEUP_BT || need_wakeup_bt == BT_WAKEUP_HOST)
+    {
+        struct sk_buff *bt_wake_buff = NULL;
+        unsigned char rdabt_fc[] = {0x01,0xc0,0xfc,0x00};
+        bt_wake_buff = bt_skb_alloc(4, GFP_ATOMIC);
+        if(bt_wake_buff)
+        {
+               memcpy(skb_put(bt_wake_buff,4), rdabt_fc, 4);
+               //atomic_set(&need_wakeup_bt, BT_SEND_WAKEUP);
+               need_wakeup_bt = BT_SEND_WAKEUP;
+               return bt_wake_buff;
+        }
+    }
+    //else if(atomic_read(&need_wakeup_bt) == BT_SEND_WAKEUP) 
+       else if(need_wakeup_bt == BT_SEND_WAKEUP)       
+          return NULL;
+#endif
+
        if (!skb)
                skb = hu->proto->dequeue(hu);
        else
index 1fc9173dec5f4a447c50002633d3b7cb4100a735..b2e9e9611210a2e3df6d52905cf2ef52fa516c35 100755 (executable)
@@ -80,7 +80,7 @@ int debug_level = 5;
     #define RK29_SDMMC0DETECTN_GPIO RK30_PIN3_PB6
     #define RK29_SDMMC0PWREN_GPIO   RK30_PIN3_PA7
 #elif defined(CONFIG_ARCH_RK2928)
-    #define RK29_SDMMC0DETECTN_GPIO RK2928_PIN1_PC7
+    #define RK29_SDMMC0DETECTN_GPIO RK2928_PIN1_PC1
     #define RK29_SDMMC0PWREN_GPIO   RK2928_PIN1_PB6
 #endif
 
@@ -2576,6 +2576,15 @@ static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
     
 }
 
+//+++RDA+++
+struct mmc_host *mmc_prt;
+void rk29_sdio_irq_enable(int enable)
+{
+       rk29_sdmmc_enable_sdio_irq(mmc_prt, enable);
+}
+EXPORT_SYMBOL(rk29_sdio_irq_enable);
+//+++RDA+++
+
 static void  rk29_sdmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
 {
         card->quirks = MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
@@ -3779,7 +3788,9 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, mmc);        
 
        mmc_add_host(mmc);
-
+//+++RDA+++
+       mmc_prt = mmc;
+//+++RDA+++
 #ifdef RK29_SDMMC_NOTIFY_REMOVE_INSERTION
     
     globalSDhost[pdev->id] = (struct rk29_sdmmc        *)host;
@@ -3868,7 +3879,6 @@ static irqreturn_t det_keys_isr(int irq, void *dev_id)
 
        return IRQ_HANDLED;
 }
-
 static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
 {
        int ret = 0;
@@ -3885,7 +3895,6 @@ static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
 
        gpio_request(RK29_SDMMC0DETECTN_GPIO, "sd_detect");
        gpio_direction_input(RK29_SDMMC0DETECTN_GPIO);
-
        host->gpio_irq = gpio_to_irq(RK29_SDMMC0DETECTN_GPIO);
        ret = request_irq(host->gpio_irq, det_keys_isr,
                                            (gpio_get_value(RK29_SDMMC0DETECTN_GPIO))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING,
@@ -3893,7 +3902,6 @@ static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
                                            host);
        
        enable_irq_wake(host->gpio_irq);
-
        return ret;
 }
 static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host)
index 7f3ba322779a56b390ba59aa11f9ca4e93b19134..a9fe35801164c35b23a2381996e888e77c57e7b4 100755 (executable)
 
 #define AUTO_OFF_TIMEOUT 2000
 
+
+#ifndef RDA_BT_SUPPORT
+#define RDA_BT_SUPPORT
+#include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/time.h>
+#define BT_NVRAM_FILE_NAME "/data/misc/bluetooth/.rdabtaddr"
+
+typedef enum
+{
+    HOST_WAKEUP_BT = 1,
+    BT_WAKEUP_HOST,
+    BT_SEND_WAKEUP
+}bt_wakeup_status;
+
+struct hci_uart {
+    struct tty_struct       *tty;
+    struct hci_dev          *hdev;
+    unsigned long           flags;
+
+    struct hci_uart_proto   *proto;
+    void                    *priv;
+
+    struct sk_buff          *tx_skb;
+    unsigned long           tx_state;
+    spinlock_t              rx_lock;
+};
+
+static int nvram_read(char *filename, char *buf, ssize_t len, int offset)
+{
+    struct file *fd;
+    //ssize_t ret;
+    int retLen = -1;
+
+    mm_segment_t old_fs = get_fs();
+    set_fs(KERNEL_DS);
+
+    fd = filp_open(filename, O_WRONLY|O_CREAT, 0666);
+
+    if(IS_ERR(fd)) {
+        printk("[rda5890][nvram_read] : failed to open fd = %d !!\n" ,fd);
+        return -1;
+    }
+    do{
+        if ((fd->f_op == NULL) || (fd->f_op->read == NULL))
+        {
+            printk("[rda5890][nvram_read] : file can not be read!!\n");
+            break;
+        }
+
+        if (fd->f_pos != offset) {
+            if (fd->f_op->llseek) 
+            {
+                if(fd->f_op->llseek(fd, offset, 0) != offset) 
+                {
+                    printk("[rda5890][nvram_read] : failed to seek!!\n");
+                    break;
+                }
+            } 
+            else 
+            {
+                fd->f_pos = offset;
+            }
+        }
+
+        retLen = fd->f_op->read(fd,
+                              buf,
+                              len,
+                              &fd->f_pos);
+    }while(false);
+    
+
+    filp_close(fd, NULL);
+    set_fs(old_fs);
+    return retLen;
+}
+
+static int nvram_write(char *filename, char *buf, ssize_t len, int offset)
+{
+    struct file *fd;
+    int retLen = -1;
+
+    mm_segment_t old_fs = get_fs();
+    set_fs(KERNEL_DS);
+
+    fd = filp_open(filename, O_WRONLY|O_CREAT, 0666);
+
+    if(IS_ERR(fd)) 
+    {
+        printk("[rda5890][nvram_write] : failed to open!!\n");
+        return -1;
+    }
+    
+    do{
+        if ((fd->f_op == NULL) || (fd->f_op->write == NULL))
+        {
+            printk("[rda5890][nvram_write] : file can not be write!!\n");
+            break;
+        } /* End of if */
+
+        if (fd->f_pos != offset) 
+        {
+            if (fd->f_op->llseek) 
+            {
+                if(fd->f_op->llseek(fd, offset, 0) != offset) 
+                {
+                                    printk("[rda5890][nvram_write] : failed to seek!!\n");
+                    break;
+                }
+            } 
+            else 
+            {
+                fd->f_pos = offset;
+            }
+        }
+        
+        retLen = fd->f_op->write(fd,
+                                 buf,
+                                 len,
+                                 &fd->f_pos);
+    }while(false);
+    
+    filp_close(fd, NULL);
+    set_fs(old_fs);
+    return retLen;
+}
+
+static int rda5890_read_bt_addr(char* buf)
+{
+    return nvram_read(BT_NVRAM_FILE_NAME, buf, 6, 0);
+}
+
+static int rda5890_write_bt_addr(char * buf)
+{
+    return nvram_write(BT_NVRAM_FILE_NAME, buf, 6, 0);
+}
+
+#endif
+
 static void hci_cmd_task(unsigned long arg);
 static void hci_rx_task(unsigned long arg);
 static void hci_tx_task(unsigned long arg);
+#ifdef RDA_BT_SUPPORT
+
+volatile int need_wakeup_bt;
+//atomic_t       need_wakeup_bt;
+EXPORT_SYMBOL(need_wakeup_bt);
+
+static struct delayed_work bt_pm_delayed_work;
+static void hci_bt_pm_task(struct work_struct *work);
+extern int hci_uart_tx_wakeup(struct hci_uart *hu);
+
+#endif
 
 static DEFINE_RWLOCK(hci_task_lock);
 
@@ -541,7 +691,23 @@ int hci_dev_open(__u16 dev)
                atomic_set(&hdev->cmd_cnt, 1);
                set_bit(HCI_INIT, &hdev->flags);
                hdev->init_last_cmd = 0;
-
+#ifdef RDA_BT_SUPPORT
+               {
+                   unsigned char bt_addr_cmd[10]= {0x01,0x1a,0xfc,0x06,0x00,0x00,0x00,0x00,0x90,0x59};
+                   struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
+               struct tty_struct *tty = hu->tty;
+
+                   if(rda5890_read_bt_addr(&bt_addr_cmd[4]) != 6)
+                   {
+                       get_random_bytes(&bt_addr_cmd[4], 4);
+                       rda5890_write_bt_addr(&bt_addr_cmd[4]);
+                   }
+       
+        tty->ops->write(tty, bt_addr_cmd, 10);
+        msleep(50);    
+                   printk("bt_addr:%x:%x:%x:%x:%x:%x \n", bt_addr_cmd[4], bt_addr_cmd[5],bt_addr_cmd[6],bt_addr_cmd[7],bt_addr_cmd[8],bt_addr_cmd[9]);
+               }
+#endif
                ret = __hci_request(hdev, hci_init_req, 0,
                                        msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
@@ -563,6 +729,11 @@ int hci_dev_open(__u16 dev)
                tasklet_kill(&hdev->rx_task);
                tasklet_kill(&hdev->tx_task);
                tasklet_kill(&hdev->cmd_task);
+#ifdef RDA_BT_SUPPORT
+        cancel_delayed_work(&bt_pm_delayed_work);
+       need_wakeup_bt = -1;
+        //atomic_set(&need_wakeup_bt, -1);
+#endif
 
                skb_queue_purge(&hdev->cmd_q);
                skb_queue_purge(&hdev->rx_q);
@@ -601,7 +772,12 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        /* Kill RX and TX tasks */
        tasklet_kill(&hdev->rx_task);
        tasklet_kill(&hdev->tx_task);
-
+#ifdef RDA_BT_SUPPORT
+    cancel_delayed_work_sync(&bt_pm_delayed_work);
+       flush_scheduled_work();
+       //atomic_set(&need_wakeup_bt, -1);
+       need_wakeup_bt = -1;
+#endif
        hci_dev_lock_bh(hdev);
        inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
@@ -676,7 +852,11 @@ int hci_dev_reset(__u16 dev)
 
        hci_req_lock(hdev);
        tasklet_disable(&hdev->tx_task);
-
+#ifdef RDA_BT_SUPPORT
+       cancel_delayed_work(&bt_pm_delayed_work);
+       //atomic_set(&need_wakeup_bt, 0);
+       need_wakeup_bt = 0;
+#endif
        if (!test_bit(HCI_UP, &hdev->flags))
                goto done;
 
@@ -1485,7 +1665,11 @@ int hci_register_dev(struct hci_dev *hdev)
        tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
        tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
        tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
-
+#ifdef RDA_BT_SUPPORT    
+       //atomic_set(&need_wakeup_bt, 0);
+       need_wakeup_bt = 0;
+       INIT_DELAYED_WORK(&bt_pm_delayed_work, hci_bt_pm_task);
+#endif
        skb_queue_head_init(&hdev->rx_q);
        skb_queue_head_init(&hdev->cmd_q);
        skb_queue_head_init(&hdev->raw_q);
@@ -2347,6 +2531,17 @@ static void hci_rx_task(unsigned long arg)
        struct hci_dev *hdev = (struct hci_dev *) arg;
        struct sk_buff *skb;
 
+#ifdef RDA_BT_SUPPORT
+       struct hci_event_hdr *hdr;
+       __u8 event;
+       int action = 0;
+
+       cancel_delayed_work(&bt_pm_delayed_work);
+       //if(atomic_read(&need_wakeup_bt) >= 0)
+        if(need_wakeup_bt>=0)
+               schedule_delayed_work(&bt_pm_delayed_work, 4*HZ);
+#endif
+
        BT_DBG("%s", hdev->name);
 
        read_lock(&hci_task_lock);
@@ -2375,6 +2570,26 @@ static void hci_rx_task(unsigned long arg)
                /* Process frame */
                switch (bt_cb(skb)->pkt_type) {
                case HCI_EVENT_PKT:
+#ifdef RDA_BT_SUPPORT
+                    {
+                        hdr = (struct hci_event_hdr *) skb->data;
+                        event = hdr->evt;
+
+                        if(event == HCI_EV_CMD_COMPLETE)
+                        {
+                            //struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
+                            struct hci_ev_cmd_complete *ev = (void *) skb->data + HCI_EVENT_HDR_SIZE;
+                            if((ev->opcode == (0x3f<<10 | 0xc0)) || (ev->opcode == (0x3f<<10 | 0xc1)))
+                            {
+                                //if(hu)
+                                       //hci_uart_tx_wakeup(hu);
+                                 action = 1; 
+                                 kfree_skb(skb);
+                                 break;
+                            }
+                        }
+                    }                   
+#endif
                        hci_event_packet(hdev, skb);
                        break;
 
@@ -2395,6 +2610,21 @@ static void hci_rx_task(unsigned long arg)
        }
 
        read_unlock(&hci_task_lock);
+
+#ifdef RDA_BT_SUPPORT
+       if(action == 1)
+       {
+               struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
+
+                       //atomic_set(&need_wakeup_bt, 0);
+                need_wakeup_bt = 0;                
+               if(hu)
+               {
+                       hci_uart_tx_wakeup(hu);
+               }
+       }
+#endif
+
 }
 
 static void hci_cmd_task(unsigned long arg)
@@ -2427,3 +2657,36 @@ static void hci_cmd_task(unsigned long arg)
                }
        }
 }
+
+
+#ifdef RDA_BT_SUPPORT
+static void hci_bt_pm_task(struct work_struct *work)
+{
+    //if(atomic_read(&need_wakeup_bt) != BT_WAKEUP_HOST)
+        //atomic_set(&need_wakeup_bt, HOST_WAKEUP_BT);
+    if(need_wakeup_bt != BT_WAKEUP_HOST)
+       need_wakeup_bt = HOST_WAKEUP_BT;
+}
+
+void export_bt_hci_wakeup_chip(void)
+{
+    struct hci_dev * hdev = hci_dev_get(0);
+    struct hci_uart *hu  = NULL;
+
+    if(hdev)
+        hu = (struct hci_uart *) hdev->driver_data;
+    else
+        {
+            //atomic_set(&need_wakeup_bt, 0);
+               need_wakeup_bt = 0;
+               return ;
+        }
+    
+    //atomic_set(&need_wakeup_bt, BT_WAKEUP_HOST);  
+       need_wakeup_bt = BT_WAKEUP_HOST;
+       hci_uart_tx_wakeup(hu);
+}
+
+EXPORT_SYMBOL(export_bt_hci_wakeup_chip);
+#endif
+