[ALPS02870048] BT: Porting STEREO driver
Test: Pass
Change-Id: I7e5eef38d702e8778b9d0fbbc4b5aec66af81559
Signed-off-by: can.chen <can.chen@mediatek.com>
Feature: BT Driver
CR-Id: ALPS02870048
diff --git a/Makefile b/Makefile
index 18313ee..e8c5bba 100644
--- a/Makefile
+++ b/Makefile
@@ -13,9 +13,12 @@
# Common
###############################################################################
ifeq ($(PLATFORM),MT8516_YOCTO)
-obj-m := $(SDIO_MOD_NAME).o
+ obj-m := $(SDIO_MOD_NAME).o
+ ifeq ($(SUPPORT_MTK_BT_STEREO),yes)
+ ccflags-y += -DSUPPORT_BT_STEREO=1
+ endif
else
-obj-m := $(USB_MOD_NAME).o $(SDIO_MOD_NAME).o
+ obj-m := $(USB_MOD_NAME).o $(SDIO_MOD_NAME).o
endif
all:
diff --git a/btmtk_sdio.c b/btmtk_sdio.c
index b2d50de..516e729 100644
--- a/btmtk_sdio.c
+++ b/btmtk_sdio.c
@@ -54,6 +54,14 @@
void sdio_card_detect(int card_present);
#endif
+#if SUPPORT_BT_STEREO
+#include <linux/of.h>
+#include <linux/of_irq.h>
+struct bt_stereo_clk stereo_clk;
+unsigned int stereo_irq = 0;
+unsigned int clk_flag = 0;
+#endif
+
static dev_t g_devIDfwlog;
static struct class *pBTClass;
static struct device *pBTDev;
@@ -2239,6 +2247,49 @@
FW_DONE:
#endif
+#if SUPPORT_BT_STEREO
+ if (rxbuf[SDIO_HEADER_LEN] == 0x04
+ && rxbuf[SDIO_HEADER_LEN+1] == 0x0E
+ && rxbuf[SDIO_HEADER_LEN+2] == 0x04
+ && rxbuf[SDIO_HEADER_LEN+3] == 0x01
+ && rxbuf[SDIO_HEADER_LEN+4] == 0x02
+ && rxbuf[SDIO_HEADER_LEN+5] == 0xFD) {
+ pr_info("%s: This is btclk event, status:%02x\n",
+ __func__, rxbuf[SDIO_HEADER_LEN+6]);
+ buf_len = rx_length-(MTK_SDIO_PACKET_HEADER_SIZE+1);
+ goto exit;
+ }
+
+ /*receive BT clock data*/
+ if (rx_length >= (SDIO_HEADER_LEN+13)
+ && rxbuf[SDIO_HEADER_LEN] == 0x04
+ && rxbuf[SDIO_HEADER_LEN+1] == 0xFF
+ && rxbuf[SDIO_HEADER_LEN+3] == 0x41) {
+ pr_debug("%s: This is btclk data - %d, %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ __func__, rx_length,
+ rxbuf[SDIO_HEADER_LEN+0], rxbuf[SDIO_HEADER_LEN+1], rxbuf[SDIO_HEADER_LEN+2],
+ rxbuf[SDIO_HEADER_LEN+3], rxbuf[SDIO_HEADER_LEN+4], rxbuf[SDIO_HEADER_LEN+5],
+ rxbuf[SDIO_HEADER_LEN+6], rxbuf[SDIO_HEADER_LEN+7], rxbuf[SDIO_HEADER_LEN+8],
+ rxbuf[SDIO_HEADER_LEN+9], rxbuf[SDIO_HEADER_LEN+10], rxbuf[SDIO_HEADER_LEN+11],
+ rxbuf[SDIO_HEADER_LEN+12], rxbuf[SDIO_HEADER_LEN+13], rxbuf[SDIO_HEADER_LEN+14],
+ rxbuf[SDIO_HEADER_LEN+15], rxbuf[SDIO_HEADER_LEN+16], rxbuf[SDIO_HEADER_LEN+17]);
+
+ if (rxbuf[SDIO_HEADER_LEN+12] == 0x0) {
+ u64 intra_clk = 0, clk = 0;
+ memcpy(&intra_clk, &rxbuf[SDIO_HEADER_LEN+6], 2);
+ memcpy(&clk, &rxbuf[SDIO_HEADER_LEN+8], 4);
+ stereo_clk.fw_clk = intra_clk + (clk&0x0FFFFFFC)*3125/10;
+ clk_flag |= 0x02;
+ pr_debug("%s: btclk intra:%lx, clk:%lx, fw_clk:%ld\n", __func__, intra_clk, clk, stereo_clk.fw_clk);
+ } else {
+ pr_warning("%s: No ACL CONNECTION(%d), disable event and interrupt\n", __func__, rxbuf[SDIO_HEADER_LEN+12]);
+ }
+
+ buf_len = rx_length-(MTK_SDIO_PACKET_HEADER_SIZE+1);
+ goto exit;
+ }
+#endif
+
/*receive picus data to fwlog_queue*/
if (rx_length > (SDIO_HEADER_LEN+8)) {
dump_len = (rxbuf[SDIO_HEADER_LEN+1]&0x0F) * 256 + rxbuf[SDIO_HEADER_LEN+2];
@@ -2847,6 +2898,44 @@
return 0;
}
#endif
+
+#if SUPPORT_BT_STEREO
+static int btmtk_stereo_irq_handler(int irq, void *dev)
+{
+ /* Get sys clk */
+ struct timeval tv;
+ do_gettimeofday(&tv);
+ stereo_clk.sys_clk = tv.tv_sec*1000000 + tv.tv_usec;
+ clk_flag = 0x01;
+ pr_debug("%s: tv_sec %d, tv_usec %d sys_clk %ld\n", __func__, tv.tv_sec, tv.tv_usec, stereo_clk.sys_clk);
+ return 0;
+}
+
+static int btmtk_stereo_reg_irq(void)
+{
+ int ret;
+ struct device_node *node;
+
+ node = of_find_compatible_node(NULL, NULL, "mediatek,connectivity-combo");
+ if (node) {
+ stereo_irq = irq_of_parse_and_map(node, 1);
+ ret = request_irq(stereo_irq, (irq_handler_t) btmtk_stereo_irq_handler,
+ IRQF_TRIGGER_RISING, "BTSTEREO_ISR_Handler", NULL);
+ }
+
+ if (ret)
+ pr_err("%s fail(%d)!!! irq_number=%d\n", __func__, ret, stereo_irq);
+
+ return ret;
+}
+
+static void btmtk_stereo_unreg_irq(void)
+{
+ free_irq(stereo_irq, NULL);
+ return;
+}
+#endif
+
static int btmtk_sdio_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
@@ -2982,6 +3071,10 @@
wake_lock_init(&g_card->eint_wlock, WAKE_LOCK_SUSPEND, "btevent_eint");
#endif
+#if SUPPORT_BT_STEREO
+ btmtk_stereo_reg_irq();
+#endif
+
pr_info("%s normal end\n", __func__);
probe_ready = true;
return 0;
@@ -3000,6 +3093,10 @@
pr_info("%s begin user_rmmod %d\n", __func__, user_rmmod);
probe_ready = false;
+#if SUPPORT_BT_STEREO
+ btmtk_stereo_unreg_irq();
+#endif
+
if (func) {
card = sdio_get_drvdata(func);
if (card) {
@@ -3995,12 +4092,66 @@
return mask;
}
-long btmtk_fops_unlocked_ioctl(struct file *filp,
+static long btmtk_fops_unlocked_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
- u32 retval = 0;
+ u32 ret = 0;
+ int err = 0;
- return retval;
+#if SUPPORT_BT_STEREO
+ int cnt = 0;
+ struct bt_stereo_para stereo_para;
+ struct sk_buff *skb = NULL;
+ u8 set_btclk[] = {0x01, 0x02, 0xFD, 0x0B,
+ 0x00, 0x00, /* Handle */
+ 0x00, /* Method */
+ /* bit0~3 - 0:CVSD remove,1:GPIO,2:In-band with transport*/
+ /* bit4~7 - 0:Shared memory,1:auto event */
+ 0x00, 0x00, 0x00, 0x00, /* Period = value*0.625ms */
+ 0x09, /* GPIO num - 0x01:BGF_INT_B,0x09:GPIO0 */
+ 0x01, /* trigger mode - 0:Low,1:High */
+ 0x00, 0x00}; /* active slots = value*0.625ms */
+#endif
+
+ switch(cmd) {
+#if SUPPORT_BT_STEREO
+ case BTMTK_IOCTL_STEREO_GET_CLK:
+ pr_debug("%s: BTMTK_IOCTL_STEREO_GET_CLK cmd\n", __func__);
+ for (cnt = 100; cnt > 0; cnt--) {
+ if (clk_flag == 0x3)
+ break;
+ msleep(1);
+ }
+ if (clk_flag != 0x3)
+ return -EAGAIN;
+
+ if (copy_to_user((struct bt_stereo_clk __user*)arg, &stereo_clk, sizeof(struct bt_stereo_clk)))
+ return -EBUSY;
+ break;
+ case BTMTK_IOCTL_STEREO_SET_PARA:
+ pr_debug("%s: BTMTK_IOCTL_STEREO_SET_PARA cmd\n", __func__);
+ if (copy_from_user(&stereo_para, (struct bt_stereo_para __user*)arg, sizeof(struct bt_stereo_para)))
+ return -EBUSY;
+
+ /* Send and check HCI cmd */
+ memcpy(&set_btclk[4], &stereo_para.handle, sizeof(stereo_para.handle));
+ memcpy(&set_btclk[6], &stereo_para.method, sizeof(stereo_para.method));
+ memcpy(&set_btclk[7], &stereo_para.period, sizeof(stereo_para.period));
+ memcpy(&set_btclk[13], &stereo_para.active_slots, sizeof(stereo_para.active_slots));
+
+ skb = bt_skb_alloc(sizeof(set_btclk)-1, GFP_ATOMIC);
+ bt_cb(skb)->pkt_type = set_btclk[0];
+ memcpy(&skb->data[0], &set_btclk[1], sizeof(set_btclk)-1);
+
+ skb->len = sizeof(set_btclk)-1;
+ skb_queue_tail(&g_priv->adapter->tx_queue, skb);
+ wake_up_interruptible(&g_priv->main_thread.wait_q);
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+ return ret;
}
static int btmtk_fops_openfwlog(struct inode *inode,
diff --git a/btmtk_sdio.h b/btmtk_sdio.h
index 486daff..7dc3782 100644
--- a/btmtk_sdio.h
+++ b/btmtk_sdio.h
@@ -19,7 +19,7 @@
#endif
-#define VERSION "v0.0.0.52_2018070901_YOCTO"
+#define VERSION "v0.0.0.53_2018072701_YOCTO"
#define SDIO_HEADER_LEN 4
@@ -323,6 +323,31 @@
#define COMPARE_SUCCESS 1
#define WOBLE_COMP_EVENT_TIMO 5000
+/**
+ * BTMTK ioctl
+ */
+
+#define BTMTK_IOCTL_MAGIC 'k'
+
+#if SUPPORT_BT_STEREO
+#define BTMTK_IOCTL_STEREO_GET_CLK _IOR(BTMTK_IOCTL_MAGIC, 1, void *)
+#define BTMTK_IOCTL_STEREO_SET_PARA _IOW(BTMTK_IOCTL_MAGIC, 2, void *)
+#endif
+
+
+#if SUPPORT_BT_STEREO
+struct bt_stereo_clk {
+ u64 sys_clk;
+ u64 fw_clk;
+};
+
+struct bt_stereo_para {
+ u16 handle;
+ u8 method;
+ u32 period;
+ u16 active_slots;
+};
+#endif
/**
* Inline functions