summaryrefslogtreecommitdiff
path: root/drivers/bluetooth/wmt_rfkill_bluetooth.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/wmt_rfkill_bluetooth.c')
-rwxr-xr-xdrivers/bluetooth/wmt_rfkill_bluetooth.c383
1 files changed, 383 insertions, 0 deletions
diff --git a/drivers/bluetooth/wmt_rfkill_bluetooth.c b/drivers/bluetooth/wmt_rfkill_bluetooth.c
new file mode 100755
index 00000000..476f1ab0
--- /dev/null
+++ b/drivers/bluetooth/wmt_rfkill_bluetooth.c
@@ -0,0 +1,383 @@
+/*
+ * arch/arm/mach-wmt/wmt_rfkill_bluetooth.c
+ * Copyright (c) RubbitXiao RubbitXiao@wondermedia.com.cn
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * wonderMedia bluetooth "driver"
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/rfkill.h>
+#include <asm/io.h>//for readb/writeb
+#include <mach/hardware.h>//WMT_MMAP_OFFSET
+#include <linux/pwm.h> //for pwm
+#include <mach/wmt_iomux.h>
+
+
+#define DRV_NAME "wmt-bt"
+
+static int pwren_num = -1;
+static int active_level = -1;
+static int gpio_int_num = -1;
+static int src_32K =1;
+enum LEVEL {
+ LOW = 0,
+ HIGH,
+};
+enum POWER_CTRL {
+ POWER_DIS = 0,
+ POWER_EN,
+};
+
+extern int wmt_getsyspara(char *varname, char *varval, int *varlen);
+void pwm_set_enable(int no,int enable);
+void pwm_set_freq(int no,unsigned int freq);
+void pwm_set_level(int no,unsigned int level);
+int bluetooth_power_ctrl(int gpio_num, int enable,int active_level);
+//configure pwm1/2 pin
+void config_pwm_pin(int pwm_num,int enable)
+{
+ int val;
+ if(enable) {
+ val = readb(0xd8110200+WMT_MMAP_OFFSET);
+ val &= ~(1 << 7);
+ writeb(val, 0xd8110200+WMT_MMAP_OFFSET);
+ }else{
+ val = readb(0xd8110200+WMT_MMAP_OFFSET);
+ val |= (1 << 7);
+ writeb(val, 0xd8110200+WMT_MMAP_OFFSET);
+ }
+}
+
+static struct pwm_device * g_pwm =NULL;
+DEFINE_SPINLOCK(pwm_lock);
+static volatile int g_pwm_enable = 0x00;
+
+static int enable_pwm_32KHz(int pwm_num,int enable)
+{
+ if(enable) {
+ if(!g_pwm){
+ g_pwm = pwm_request(pwm_num,"bluetooth 32KHz");
+ if(!g_pwm){
+ printk("can not request pwm1 for bluetooth mtk6622\n");
+ return -ENOMEM;
+ }
+ }
+ //pwm_config(g_pwm, 15625, 31250);// configuration output 32KHZ
+ pwm_config(g_pwm, 15258, 30517);// configuration output 32768HZ
+ pwm_enable(g_pwm);
+ config_pwm_pin(pwm_num,0x01);
+ printk("enable 32khz output\n");
+ mdelay(200);
+ }else{
+ pwm_disable(g_pwm);
+ config_pwm_pin(pwm_num,0x00);
+ printk("disable 32khz output\n");
+ }
+ return 0;
+}
+
+/*
+* TODO: should atomis operation
+*/
+int enable_32Khz(int enable)
+{
+ int val;
+ val = readb(0xd8110203+WMT_MMAP_OFFSET);
+ if(enable)
+ {
+ val |= (1 << 4);
+ }else
+ {
+ val &= ~(1 << 4);
+ }
+ writeb(val, 0xd8110203+WMT_MMAP_OFFSET);
+ return 0;
+}
+
+
+static void realease_pwm(void)
+{
+ if(g_pwm)
+ pwm_free(g_pwm);
+ g_pwm = NULL;
+}
+
+
+int pwm_32KHZ_control(int enable)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&pwm_lock, flags);
+ if(enable){
+ enable_pwm_32KHz(src_32K,1);
+ }else{
+ enable_pwm_32KHz(src_32K,0);
+ }
+ printk("enable:%d\n",enable);
+ spin_unlock_irqrestore(&pwm_lock, flags);
+}
+EXPORT_SYMBOL(pwm_32KHZ_control);
+
+/* Bluetooth control */
+static void bt_enable(int on)
+{
+ if (on) {
+ printk("bt_enable on:%d\n",on);
+ if(src_32K == 4){
+ enable_32Khz(1);
+ }else{
+ pwm_32KHZ_control(1);
+ }
+ mdelay(50);
+ /* Power on the chip */
+ //gpio_set_value(pwren_num, 1);,&
+ bluetooth_power_ctrl(pwren_num, POWER_EN,active_level);
+ mdelay(100);
+ }
+ else {
+ printk("bt_enable on:%d\n",on);
+ //gpio_set_value(pwren_num, 0);
+ bluetooth_power_ctrl(pwren_num, POWER_DIS,active_level);
+ mdelay(50);
+ if(src_32K == 4){
+ //enable_32Khz(0);
+ }else{
+ //pwm_32KHZ_control(0);
+ }
+ mdelay(100);
+ }
+}
+
+static int bt_set_block(void *data, bool blocked)
+{
+ bt_enable(!blocked);
+ return 0;
+}
+
+static const struct rfkill_ops bt_rfkill_ops = {
+ .set_block = bt_set_block,
+};
+
+#include "test_skeleton.c" //for test_skeleton_proc_init()
+
+
+int bluetooth_power_ctrl(int gpio_num, int enable,int active_level)
+{
+ if(enable){
+ /*for power enable gpio pin*/
+ if(active_level)
+ gpio_direction_output(gpio_num, HIGH);
+ else
+ gpio_direction_output(gpio_num, LOW);
+ }else{
+ if(active_level)
+ gpio_direction_output(gpio_num, LOW);
+ else
+ gpio_direction_output(gpio_num, HIGH);
+ }
+
+ return 0;
+}
+
+
+static int __devinit bt_probe(struct platform_device *pdev)
+{
+ struct rfkill *rfk;
+ int ret = 0;
+
+ char buf[256];
+ int varlen = 256;
+
+
+ /*
+ * wmt.bt.brcm formater as follows:
+ * pwren_num:active_level:gpio_int_num:src_32K
+ * for example: 151:1:0
+ * src_32K:
+ * 1:pwm1
+ * 2:pwm2
+ * 3:pwm3
+ * 4:susgpio3 cpu output 32KHz
+ *
+ * for 8723bs_bt modules on SK_WAVE7_FT5316_BET-CT070040 gpio14 as bt power enable
+ * setenv wmt.bt.brcm 14:1:0:4
+ * for ap6330 bt modules on 30KT susgpio2 as bt power enable
+ * setenv wmt.bt.brcm 151:1:0:4
+ */
+ if(wmt_getsyspara("wmt.bt.brcm",buf,&varlen) == 0)
+ {
+ sscanf(buf,"%d:%d:%d:%d",&pwren_num,&active_level,&gpio_int_num,&src_32K);
+ printk("use customized value:p%d,a%d,i%d,32K src:%d for wmt rfkill bluetooth\n",pwren_num,active_level,gpio_int_num,src_32K);
+ } else {
+ pwren_num = WMT_PIN_GP62_WAKEUP2;
+ active_level = 0x01;
+ gpio_int_num = -1;
+ src_32K = 1;
+ printk("use default value:p%d,a%d,i%d for wmt rfkill bluetooth\n",pwren_num,active_level,gpio_int_num);
+
+ }
+
+#if 1
+ /*for power enable gpio pin*/
+ ret = gpio_request(pwren_num, "rfkill bluetooth power/reset pin");
+ if(ret < 0) {
+ printk("request gpio:%x failed!!! for rfkill bluetooth\n",pwren_num);
+ goto err_rfk_alloc;
+ }else{
+ printk("request gpio:%d for rfkill bluetooth success!!!\n",pwren_num);
+ }
+
+ ret = gpio_request(WMT_PIN_GP1_GPIO14, "bt_wakeup");
+ if (ret < 0)
+ printk("reuqest bt_wakeup gpio failed!\n");
+ else
+ printk("reuqest bt_wakeup gpio sucessful!\n");
+ gpio_direction_output(WMT_PIN_GP1_GPIO14, 1);
+#endif
+ bluetooth_power_ctrl(pwren_num, POWER_DIS, active_level);
+
+#if 0
+ /*for bt wakeup gpio pin*/
+ ret = gpio_request(WMT_PIN_GP1_GPIO14, "bluetooth wakeup pin");
+ if(ret < 0) {
+ printk("request gpio:%x failed!!! bluetooth wakeup pin\n",WMT_PIN_GP1_GPIO14);
+ goto err_rfk_alloc;
+ }else{
+ printk("request gpio:%d for bluetooth wakeup pin success!!!\n",WMT_PIN_GP1_GPIO14);
+ }
+ gpio_direction_output(WMT_PIN_GP1_GPIO14, HIGH);
+#endif
+
+ /* Configures BT serial port GPIOs */
+ //this jobs is doned in uart serial drivers
+#if 0
+ //first disable bluetooth module during system booting stage.
+ if(active_level)
+ gpio_direction_output(pwren_num, LOW);
+ else
+ gpio_direction_output(pwren_num, HIGH);
+ //enable_32Khz(0x00); //disable susgpio3 ouput 32Khz, which lead to system hangup and can not enter suspend.
+#endif
+
+ if(!g_pwm && src_32K < 4){
+ printk("begint to pwm request\n");
+ g_pwm = pwm_request(src_32K,"bluetooth 32KHz");
+ if(!g_pwm){
+ printk("can not request pwm1 for bluetooth mtk6622\n");
+ ret = -ENOMEM;
+ goto err_rfk_alloc;
+ }
+ }else{
+ enable_32Khz(1);
+ }
+
+ rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
+ &bt_rfkill_ops, NULL);
+ if (!rfk) {
+ ret = -ENOMEM;
+ goto err_rfk_alloc;
+ }
+
+ ret = rfkill_register(rfk);
+ if (ret)
+ goto err_rfkill;
+
+ platform_set_drvdata(pdev, rfk);
+ test_skeleton_proc_init();
+ return 0;
+
+err_rfkill:
+ rfkill_destroy(rfk);
+err_rfk_alloc:
+ return ret;
+}
+
+
+
+
+
+static int bt_remove(struct platform_device *pdev)
+{
+ struct rfkill *rfk = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (rfk) {
+ rfkill_unregister(rfk);
+ rfkill_destroy(rfk);
+ }
+ rfk = NULL;
+ bt_enable(0);
+ gpio_free(pwren_num);
+ //gpio_free(WMT_PIN_GP1_GPIO9);
+ gpio_free(WMT_PIN_GP1_GPIO14);
+ if(src_32K<4)
+ realease_pwm();
+ deinit_proc_init();
+ return 0;
+}
+static int bt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ pwm_32KHZ_control(0);
+ if(src_32K<4)
+ realease_pwm();
+ printk("bt_suspend");
+ return 0;
+}
+static int bt_resume(struct platform_device *pdev)
+{
+ pwm_32KHZ_control(1);
+ printk("bt_resume");
+ return 0;
+
+}
+
+static struct platform_driver bt_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = bt_probe,
+ .remove = bt_remove,
+ .suspend = bt_suspend,
+ .resume = bt_resume,
+};
+
+static void bt_device_release(struct device * dev) {}
+
+static struct platform_device device_bluetooth = {
+ .name = DRV_NAME,
+ .id = -1,
+ .dev = {
+ .release = bt_device_release,
+ }
+};
+
+static int __init bt_init(void)
+{
+ platform_device_register(&device_bluetooth);
+ return platform_driver_register(&bt_driver);
+}
+
+static void __exit bt_exit(void)
+{
+ platform_driver_unregister(&bt_driver);
+ platform_device_unregister(&device_bluetooth);
+}
+
+module_init(bt_init);
+module_exit(bt_exit);
+
+MODULE_AUTHOR("RubbitXiao RubbitXiao@wondermedia.com.cn");
+MODULE_DESCRIPTION("Driver for the common wondermedia bluetooth chip");
+MODULE_LICENSE("GPL");