1、电路图兼容速鼎WIFI和BT模块

2、涉及到的接口和管脚如下:

WIFI涉及到的管脚:
power管脚:
VCC_WIFI(wlan_power)<---->aldo1
IO_VDD(wlan_io_regulator)<---->aldo1
使能管脚:
WIFI_PDn(PL07)
WIFI_WAKE(PL05)
数据接口:
SD_CMD<---->PG01
SD_CLK<---->PG00
SD_D0 <---->PG02
SD_D1 <---->PG03
SD_D2 <---->PG04
SD_D3 <---->PG05
时钟频率:使用低速1500000

BT涉及到的管脚:
控制管脚:
AP_WAKE_BT<---->PL06
BT_LDO_EN<----->PL07
BT_POWER <------>VCC_CTP(CLDO1-3.3V)
通信管脚:
UART1_TXD<----->PG06
UART1_RXD<----->PG07
UART1_RTS<----->PG08
UART1_CTS<----->PG09
PCM蓝牙音频通路管脚(对应I2S1,需要配置成PCM模式):
PCM_SYNC<------->PG10
PCM_BCLK<------->PG11
PCM_DO  <------->PG12
PCO_DI  <------->PG13
32K_OUT <------->PG14

3、WIFI部分的系统管脚配置

lichee\tools\pack\chips\sun8iw17p1\configs\k23x3-wb\sys_config.fex
;sdio1配置
[sdc1]
sdc1_used          = 1
bus-width          = 4
sdc1_clk           = port:PG00<2><1><0><default>
sdc1_cmd           = port:PG01<2><1><0><default>
sdc1_d0            = port:PG02<2><1><0><default>
sdc1_d1            = port:PG03<2><1><0><default>
sdc1_d2            = port:PG04<2><1><0><default>
sdc1_d3            = port:PG05<2><1><0><default>
;non-removable      =
;cd-gpios           =
;sunxi-power-save-mode =
ctl-spec-caps      = 0x1
sunxi-power-save-mode =
sunxi-dis-signal-vol-sw =
;sd-uhs-sdr50       =
;sd-uhs-ddr50       =
;sd-uhs-sdr104      =
;cap-sdio-irq       =
keep-power-in-suspend   =
ignore-pm-notify    =
;max-frequency          = 150000000
min-frequency = 150000;WIFI和BT管脚配置
;--------------------------------------------------------------------------------
;wlan configuration
;wlan_used:         0-not use, 1- use
;wlan_busnum:       sdio/usb index
;clocks:            external low power clock input (32.768KHz)
;wlan_power:        input supply voltage
;wlan_io_regulator: wlan/sdio I/O voltage
;wlan_regon:        power up/down internal regulators used by wifi section
;wlan_hostwake:     wlan to wake-up host
;wlan_clk_gpio:     wlan low power clock output pin
;--------------------------------------------------------------------------------
[wlan]
compatible = "allwinner,sunxi-wlan"
wlan_used           = 1
wlan_busnum         = 1
;wlan_usbnum         = 2
;clocks             = "&clk_outa"
wlan_power          = "vcc-wifi"
;wlan_power_ext      = "dvdd-csi"
;wlan_io_regulator   = "vcc-io-wifi"
wlan_io_regulator   = "vcc-wifi"
wlan_regon          = port:PL04<1><default><default><0>
wlan_hostwake       = port:PL05<6><default><default><0>
;wlan_clk_gpio       = port:PI12<4><default><default><0>;--------------------------------------------------------------------------------
;bluetooth configuration
;bt_used:           0- no used, 1- used
;clocks:            external low power clock input (32.768KHz)
;bt_power:          input supply voltage
;bt_io_regulator:   bluetooth I/O voltage
;bt_rst_n:          power up/down internal regulators used by BT section
;--------------------------------------------------------------------------------
[bt]
bt_used             = 1
compatible = "allwinner,sunxi-bt"
bt_power            = "vcc-ctp"
;clocks             = 0x55
bt_rst_n            = port:PL07<1><default><default><0>
ap_wakeup_bt        = port:PL06<1><default><1><0>

4、WIFI部分的上电时序,BT部分后面再写

struct sunxi_wlan_platdata {int bus_index;struct regulator *wlan_power;struct regulator *wlan_power_ext;struct regulator *io_regulator;struct clk *lpo;int gpio_wlan_regon;int gpio_wlan_hostwake;int gpio_chip_en;char *wlan_power_name;char *wlan_power_ext_name;char *io_regulator_name;int power_state;int enable_state;struct platform_device *pdev;
};
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/rfkill.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/sunxi-gpio.h>
#ifdef CONFIG_PM
#include <linux/pm.h>
#endif
#include <linux/pm_runtime.h>#include <linux/etherdevice.h>
#include <linux/crypto.h>
#include <linux/miscdevice.h>
#include <linux/capability.h>#include "sunxi-rfkill.h"#define USE_HOSC_24Mstatic struct sunxi_wlan_platdata *wlan_data = NULL;//static char *project_name = CONFIG_PROJECT_NAME;
static int g_wifi_module = 0;  //default xradio
static int sunxi_wlan_on(struct sunxi_wlan_platdata *data, bool on_off);
static int sunxi_wlan_enable(struct sunxi_wlan_platdata *data, bool enable);
static DEFINE_MUTEX(sunxi_wlan_mutex);unsigned int wlan_power = 0;
void sunxi_wlan_set_enable(bool enable)
{struct platform_device *pdev;int ret = 0;if (!wlan_data)return;pdev = wlan_data->pdev;mutex_lock(&sunxi_wlan_mutex);if (enable != wlan_data->enable_state) {ret = sunxi_wlan_enable(wlan_data, enable);if (ret)dev_err(&pdev->dev, "set enable failed\n");}mutex_unlock(&sunxi_wlan_mutex);wlan_power = enable;dev_info(&pdev->dev,"%s,%d\n",__func__,enable);
}
EXPORT_SYMBOL(wlan_power);
EXPORT_SYMBOL_GPL(sunxi_wlan_set_enable);void sunxi_wlan_set_power(bool on_off)
{struct platform_device *pdev;int ret = 0;if (!wlan_data)return;pdev = wlan_data->pdev;mutex_lock(&sunxi_wlan_mutex);if(on_off != wlan_data->power_state){ret = sunxi_wlan_on(wlan_data, on_off);if(ret)dev_err(&pdev->dev,"set power failed\n");}mutex_unlock(&sunxi_wlan_mutex);
}
EXPORT_SYMBOL_GPL(sunxi_wlan_set_power);//nwd-zhaojr add for recognize wifi module
void sunxi_wlan_set_module(int flag)
{printk("nwd-wangtao set wifi module : %s\n", flag?"xr829":"xradio");g_wifi_module = flag;
}
EXPORT_SYMBOL_GPL(sunxi_wlan_set_module);int sunxi_wlan_get_bus_index(void)
{struct platform_device *pdev;pr_err("%s ---sunxi_wlan_get_bus_index()\n", __FUNCTION__);if (!wlan_data)return -EINVAL;pdev = wlan_data->pdev;dev_info(&pdev->dev,"bus_index: %d\n",wlan_data->bus_index);return wlan_data->bus_index;
}
EXPORT_SYMBOL_GPL(sunxi_wlan_get_bus_index);int sunxi_wlan_get_oob_irq(void)
{struct platform_device *pdev;int host_oob_irq = 0;if (!wlan_data || !gpio_is_valid(wlan_data->gpio_wlan_hostwake))return 0;pdev = wlan_data->pdev;host_oob_irq = gpio_to_irq(wlan_data->gpio_wlan_hostwake);if (IS_ERR_VALUE(host_oob_irq)) dev_err(&pdev->dev,"map gpio [%d] to virq failed, errno = %d\n",wlan_data->gpio_wlan_hostwake,host_oob_irq);return host_oob_irq;
}
EXPORT_SYMBOL_GPL(sunxi_wlan_get_oob_irq);int sunxi_wlan_get_oob_irq_flags(void)
{int oob_irq_flags;if (!wlan_data)return 0;oob_irq_flags = (IRQF_TRIGGER_HIGH | IRQF_SHARED | IRQF_NO_SUSPEND);return oob_irq_flags;
}
EXPORT_SYMBOL_GPL(sunxi_wlan_get_oob_irq_flags);static int sunxi_wlan_enable(struct sunxi_wlan_platdata *data, bool enable)
{struct platform_device *pdev = data->pdev;struct device *dev = &pdev->dev;if (gpio_is_valid(data->gpio_wlan_regon)) {if (enable) {gpio_direction_output(data->gpio_wlan_regon, 1);} else {gpio_direction_output(data->gpio_wlan_regon, 0);}dev_info(dev, "set wlan enable: %s\n", enable ? "1" : "0");}wlan_data->enable_state = enable;return 0;
}static int sunxi_wlan_on(struct sunxi_wlan_platdata *data, bool on_off)
{struct platform_device *pdev = data->pdev;struct device *dev = &pdev->dev;int ret = 0;pr_err("%s ---sunxi_wlan_on()\n", __FUNCTION__);pr_err("sunxi_wlan_on()--regulator--:on_off: %d\n",on_off);//if (!on_off && gpio_is_valid(data->gpio_wlan_regon))//  gpio_set_value(data->gpio_wlan_regon, 0);if (data->wlan_power_name) {data->wlan_power = regulator_get(dev, data->wlan_power_name);if (!IS_ERR(data->wlan_power)) {if (on_off) {regulator_set_voltage(data->wlan_power,(int)3300*1000,(int)3300*1000);ret = regulator_enable(data->wlan_power);if (ret < 0) {dev_err(dev, "regulator wlan_power enable failed\n");regulator_put(data->wlan_power);return ret;}ret = regulator_get_voltage(data->wlan_power);if (ret < 0) {dev_err(dev, "regulator wlan_power get voltage failed\n");regulator_put(data->wlan_power);return ret;}dev_info(dev, "check wlan wlan_power voltage: %d\n",ret);} else {ret = regulator_disable(data->wlan_power);if (ret < 0) {dev_err(dev, "regulator wlan_power disable failed\n");regulator_put(data->wlan_power);return ret;}}regulator_put(data->wlan_power);}}
#if 0 //no useif (data->wlan_power_ext_name) {data->wlan_power_ext = regulator_get(dev, data->wlan_power_ext_name);if (!IS_ERR(data->wlan_power_ext)) {if (on_off) {regulator_set_voltage(data->wlan_power_ext,(int)3300*1000,(int)3300*1000);//(int)1800*1000,//(int)1800*1000);ret = regulator_enable(data->wlan_power_ext);if (ret < 0) {dev_err(dev, "regulator wlan_power_ext enable failed\n");regulator_put(data->wlan_power_ext);//return ret;}ret = regulator_get_voltage(data->wlan_power_ext);if (ret < 0) {dev_err(dev, "regulator wlan_power_ext get voltage ""failed\n");regulator_put(data->wlan_power_ext);//return ret;}dev_info(dev, "check wlan BT power wlan_power_ext voltage: %d\n",ret);} else {ret = regulator_disable(data->wlan_power_ext);if (ret < 0) {dev_err(dev, "regulator wlan_power_ext disable failed\n");regulator_put(data->wlan_power_ext);//return ret;}}regulator_put(data->wlan_power_ext);}}
#endifif(data->io_regulator_name){data->io_regulator = regulator_get(dev, data->io_regulator_name);if (!IS_ERR(data->io_regulator)) {if(on_off){ret = regulator_enable(data->io_regulator);if (ret < 0){dev_err(dev, "regulator io_regulator enable failed\n");regulator_put(data->io_regulator);return ret;}ret = regulator_get_voltage(data->io_regulator);if (ret < 0){dev_err(dev, "regulator io_regulator get voltage failed\n");regulator_put(data->io_regulator);return ret;}dev_info(dev, "check wlan io_regulator voltage: %d\n",ret);}else{ret = regulator_disable(data->io_regulator);if (ret < 0){dev_err(dev, "regulator io_regulator disable failed\n");regulator_put(data->io_regulator);return ret;}}regulator_put(data->io_regulator);}}//   if (on_off && gpio_is_valid(data->gpio_wlan_regon)) {
//      mdelay(10);
//      gpio_set_value(data->gpio_wlan_regon, 1);
//  }wlan_data->power_state = on_off;return 0;
}static ssize_t power_state_show(struct device *dev,struct device_attribute *attr, char *buf)
{pr_err("%s ---power_state_show()\n", __FUNCTION__);return sprintf(buf, "%d\n", wlan_data->power_state);
}static ssize_t power_state_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count)
{unsigned long state;int err;pr_err("%s ---power_state_store()\n", __FUNCTION__);if (!capable(CAP_NET_ADMIN))return -EPERM;err = kstrtoul(buf, 0, &state);if (err)return err;if (state > 1)return -EINVAL;pr_err("power_state_store():state: %d\n",state);mutex_lock(&sunxi_wlan_mutex);if (state != wlan_data->power_state) {err = sunxi_wlan_on(wlan_data, state);if (err)dev_err(dev, "set power failed\n");}mutex_unlock(&sunxi_wlan_mutex);return count;
}static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR | S_IWGRP,power_state_show, power_state_store);static ssize_t enable_state_show(struct device *dev,struct device_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", wlan_data->enable_state);
}static ssize_t enable_state_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count)
{unsigned long state;int err;if (!capable(CAP_NET_ADMIN))return -EPERM;err = kstrtoul(buf, 0, &state);if (err)return err;if (state > 1)return -EINVAL;mutex_lock(&sunxi_wlan_mutex);if (state != wlan_data->enable_state) {err = sunxi_wlan_enable(wlan_data, state);if (err)dev_err(dev,"set enable failed\n");}mutex_unlock(&sunxi_wlan_mutex);return count;
}//static DEVICE_ATTR(enable_state, S_IWUGO | S_IRUGO,
//      enable_state_show, enable_state_store);
static DEVICE_ATTR(enable_state, S_IRUGO | S_IWUSR | S_IWGRP,enable_state_show, enable_state_store);static ssize_t scan_device_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count)
{unsigned long state;int err;int bus = wlan_data->bus_index;pr_err("%s ---scan_device_store()\n", __FUNCTION__);err = kstrtoul(buf, 0, &state);if (err)return err;//sunxi_wl_chipen_set(0, state);dev_info(dev, "scan_device_store()::start scan device on bus_index: %d state:%d\n",wlan_data->bus_index,state);if (bus < 0) {dev_err(dev, "scan device fail!\n");return -1;}sunxi_mmc_rescan_card(bus);return count;
}
static DEVICE_ATTR(scan_device, S_IRUGO | S_IWUSR | S_IWGRP,NULL, scan_device_store);extern void sunxi_mmc_remove_sdio(unsigned ids);
static ssize_t remove_card_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count)
{int bus = wlan_data->bus_index;dev_info(dev, "start remove card on bus_index: %d\n",wlan_data->bus_index);if (bus < 0) {dev_err(dev, "remove card fail!\n");return -1;}sunxi_mmc_remove_sdio(bus);return count;
}
static DEVICE_ATTR(remove_card, S_IRUGO | S_IWUSR | S_IWGRP,NULL, remove_card_store);
static struct attribute *misc_attributes[] = {&dev_attr_enable_state.attr,&dev_attr_scan_device.attr,&dev_attr_remove_card.attr,&dev_attr_power_state.attr,    NULL,
};static struct attribute_group misc_attribute_group = {.name  = "rf-ctrl",.attrs = misc_attributes,
};static struct miscdevice sunxi_wlan_dev = {.minor = MISC_DYNAMIC_MINOR,.name  = "sunxi-wlan",
};static char wifi_mac_str[18] = {0};void sunxi_wlan_chipid_mac_address(u8 *mac)
{
#define MD5_SIZE    16
#define CHIP_SIZE   16struct crypto_hash *tfm;struct hash_desc desc;struct scatterlist sg;u8 result[MD5_SIZE];u8 chipid[CHIP_SIZE];int i = 0;int ret = -1;memset(chipid, 0, sizeof(chipid));memset(result, 0, sizeof(result));sunxi_get_soc_chipid((u8 *)chipid);tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);if (IS_ERR(tfm)) {pr_err("Failed to alloc md5\n");return;}desc.tfm = tfm;desc.flags = 0;ret = crypto_hash_init(&desc);if (ret < 0) {pr_err("crypto_hash_init() failed\n");goto out;}sg_init_one(&sg, chipid, sizeof(chipid) - 1);ret = crypto_hash_update(&desc, &sg, sizeof(chipid) - 1);if (ret < 0) {pr_err("crypto_hash_update() failed for id\n");goto out;}crypto_hash_final(&desc, result);if (ret < 0) {pr_err("crypto_hash_final() failed for result\n");goto out;}/* Choose md5 result's [0][2][4][6][8][10] byte as mac address */for (i = 0; i < 6; i++)mac[i] = result[2*i];mac[0] &= 0xfe;     /* clear multicast bit */mac[0] &= 0xfd;     /* clear local assignment bit (IEEE802) */out:crypto_free_hash(tfm);
}
EXPORT_SYMBOL(sunxi_wlan_chipid_mac_address);void sunxi_wlan_custom_mac_address(u8 *mac)
{int i;char *p = wifi_mac_str;u8 mac_addr[ETH_ALEN] = {0};if (0 == strlen(p))return;for (i = 0; i < ETH_ALEN; i++, p++)mac_addr[i] = simple_strtoul(p, &p, 16);memcpy(mac, mac_addr, sizeof(mac_addr));
}
EXPORT_SYMBOL(sunxi_wlan_custom_mac_address);#ifndef MODULE
static int __init set_wlan_mac_addr(char *str)
{char *p = str;if (str != NULL && *str)strlcpy(wifi_mac_str, p, 18);return 0;
}
__setup("wifi_mac=", set_wlan_mac_addr);
#endifstatic int sunxi_wlan_probe(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node;struct device *dev = &pdev->dev;struct sunxi_wlan_platdata *data;struct gpio_config config;u32 val;const char *power, *io_regulator, *power_ext;int ret = 0;
#ifdef USE_HOSC_24Mvoid __iomem *vaddr;
#endifpr_err("%s ---sunxi_wlan_probe()\n", __FUNCTION__);data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);if (!dev)return -ENOMEM;data->pdev = pdev;wlan_data = data;data->bus_index = -1;if (!of_property_read_u32(np, "wlan_busnum", &val)) {switch (val) {case 0:case 1:case 2:data->bus_index = val;break;default:dev_err(dev, "unsupported wlan_busnum (%u)\n", val);return -EINVAL;}}dev_info(dev, "wlan_busnum (%u)\n", val);if (of_property_read_string(np, "wlan_power", &power)) {dev_warn(dev, "Missing wlan_power.\n");} else {data->wlan_power_name = devm_kzalloc(dev, 64, GFP_KERNEL);if (!data->wlan_power_name)return -ENOMEM;strcpy(data->wlan_power_name, power);}dev_info(dev, "wlan_power_name (%s)\n", data->wlan_power_name);
#if 0 //no useif (of_property_read_string(np, "wlan_power_ext", &power_ext)) {dev_warn(dev, "Missing wlan_power_ext.\n");} else {data->wlan_power_ext_name = devm_kzalloc(dev, 64, GFP_KERNEL);if (!data->wlan_power_ext_name)return -ENOMEM;strcpy(data->wlan_power_ext_name, power_ext);}dev_info(dev, "wlan_power_ext_name (%s)\n", data->wlan_power_ext_name);
#endifif (of_property_read_string(np, "wlan_io_regulator", &io_regulator)) {dev_warn(dev, "Missing wlan_io_regulator.\n");} else {data->io_regulator_name = devm_kzalloc(dev, 64, GFP_KERNEL);if (!data->io_regulator_name)return -ENOMEM;strcpy(data->io_regulator_name, io_regulator);}dev_info(dev, "io_regulator_name (%s)\n", data->io_regulator_name);data->gpio_wlan_regon = of_get_named_gpio_flags(np, "wlan_regon",0, (enum of_gpio_flags *)&config);if (!gpio_is_valid(data->gpio_wlan_regon)) {dev_err(dev, "get gpio wlan_regon failed\n");} else {dev_info(dev, "wlan_regon gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",config.gpio,config.mul_sel,config.pull,config.drv_level,config.data);ret = devm_gpio_request(dev, data->gpio_wlan_regon,"wlan_regon");if (ret < 0) {dev_err(dev, "can't request wlan_regon gpio %d\n",data->gpio_wlan_regon);return ret;}ret = gpio_direction_output(data->gpio_wlan_regon, 0);if (ret < 0) {dev_err(dev, "can't request output direction wlan_regon gpio %d\n",data->gpio_wlan_regon);return ret;}}
#if 0 //no usedata->gpio_chip_en = of_get_named_gpio_flags(np, "chip_en",0, (enum of_gpio_flags *)&config);if (!gpio_is_valid(data->gpio_chip_en)) {dev_err(dev, "get gpio chip_en failed\n");} else {dev_info(dev, "chip_en gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",config.gpio,config.mul_sel,config.pull,config.drv_level,config.data);ret = devm_gpio_request(dev, data->gpio_chip_en, "chip_en");if (ret < 0) {dev_err(dev, "can't request chip_en gpio %d\n",data->gpio_chip_en);return ret;}ret = gpio_direction_output(data->gpio_chip_en, 0);if (ret < 0) {dev_err(dev, "can't request output direction chip_en gpio %d\n",data->gpio_chip_en);return ret;}}
#endifdata->gpio_wlan_hostwake = of_get_named_gpio_flags(np, "wlan_hostwake",0, (enum of_gpio_flags *)&config);if (!gpio_is_valid(data->gpio_wlan_hostwake)) {dev_err(dev, "get gpio wlan_hostwake failed\n");} else {dev_info(dev,"wlan_hostwake gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",config.gpio,config.mul_sel,config.pull,config.drv_level,config.data);ret = devm_gpio_request(dev, data->gpio_wlan_hostwake,"wlan_hostwake");if (ret < 0) {dev_err(dev, "can't request wlan_hostwake gpio %d\n",data->gpio_wlan_hostwake);return ret;}gpio_direction_input(data->gpio_wlan_hostwake);if (ret < 0) {dev_err(dev,"can't request input direction wlan_hostwake gpio %d\n",data->gpio_wlan_hostwake);return ret;}#ifdef CONFIG_PMret = enable_gpio_wakeup_src(data->gpio_wlan_hostwake);if (ret < 0) {dev_err(dev, "can't enable wakeup src for wlan_hostwake %d\n",data->gpio_wlan_hostwake);return ret;}
#endif      }
#if 0 //no usedata->lpo = devm_clk_get(dev, NULL);if (IS_ERR_OR_NULL(data->lpo)) {dev_warn(dev, "clk not config\n");} else {ret = clk_prepare_enable(data->lpo);if (ret < 0)dev_warn(dev, "can't enable clk\n");}
#endif
#ifdef USE_HOSC_24Mvaddr = ioremap(0x03001f20, sizeof(unsigned long));val = readl(vaddr);val |= 0x80000000;writel(val, vaddr);val = readl(vaddr);iounmap(vaddr);dev_info(dev, "HOSC_24M reg val is: 0x%08x\n", val);
#endifret = misc_register(&sunxi_wlan_dev);if (ret) {dev_err(dev, "sunxi-wlan register driver as misc device error!\n");return ret;}ret = sysfs_create_group(&sunxi_wlan_dev.this_device->kobj,&misc_attribute_group);if (ret) {dev_err(dev, "sunxi-wlan register sysfs create group failed!\n");return ret;}data->power_state = 0;data->enable_state = 0;if (1 != data->power_state) {sunxi_wlan_set_power(1);}return 0;
}static int sunxi_wlan_remove(struct platform_device *pdev)
{misc_deregister(&sunxi_wlan_dev);sysfs_remove_group(&(sunxi_wlan_dev.this_device->kobj),&misc_attribute_group);if (!IS_ERR_OR_NULL(wlan_data->lpo))clk_disable_unprepare(wlan_data->lpo);return 0;
}static int wlan_pm_suspend(struct device *dev)
{//struct sunxi_wlan_platdata *platdata = dev_get_drvdata(dev);printk("CONFIG_PM:enter wlan_pm_suspend.\n");if (pm_runtime_suspended(dev))return 0;//if (hw_ver == HW_VER_V1_0 || hw_ver == HW_VER_V4_0) {// //return 0;//}//sunxi_wlan_set_enable(0);sunxi_wlan_set_power(0);return 0;
}static int wlan_pm_resume(struct device *dev)
{//struct sunxi_wlan_platdata *platdata = dev_get_drvdata(dev);printk("CONFIG_PM:enter wlan_pm_resume.\n");if (pm_runtime_suspended(dev))return 0;//if (hw_ver == HW_VER_V1_0 || hw_ver == HW_VER_V4_0) {//  //return 0;//}sunxi_wlan_set_power(1);//sunxi_wlan_set_enable(1);return 0;
}static struct dev_pm_ops wlan_pm_ops = {.suspend = wlan_pm_suspend,.resume  = wlan_pm_resume,
};static const struct of_device_id sunxi_wlan_ids[] = {{ .compatible = "allwinner,sunxi-wlan" },{ /* Sentinel */ }
};static struct platform_driver sunxi_wlan_driver = {.probe    = sunxi_wlan_probe,.remove = sunxi_wlan_remove,.driver    = {.owner  = THIS_MODULE,.name    = "sunxi-wlan",.pm     = &wlan_pm_ops,.of_match_table   = sunxi_wlan_ids,},
};module_platform_driver(sunxi_wlan_driver);MODULE_DESCRIPTION("sunxi wlan driver");
MODULE_LICENSE(GPL);

5、XR829驱动的整合

将全志给的linux4.9的驱动放到lichee\linux-4.9\drivers\net\wireless\xr829这个目录,修改
lichee\linux-4.9\drivers\net\wireless\Makefile
lichee\linux-4.9\drivers\net\wireless\Kconfig
这两个文件,注意跟公版XR819模块的兼容,如下:

lichee\linux-4.9\drivers\net\wireless\Kconfig
menuconfig WLANbool "Wireless LAN"depends on !S390depends on NETselect WIRELESSdefault y---help---This section contains all the pre 802.11 and 802.11 wirelessdevice drivers. For a complete list of drivers and documentationon them refer to the wireless wiki:http://wireless.kernel.org/en/users/Drivers
//添加配置选项
config XR829_SUDING_DRIVERS_CHOOSEtristate "Choose XR829 and suding wifi&&bt support"---help---Choose XR829 or suding configuration
config XR819_DRIVERS_CHOOSEtristate "Choose XR819 wifi&&bt support"---help---Choose XR819 configurationif WLAN..............................................
source "drivers/net/wireless/mediatek/Kconfig"
source "drivers/net/wireless/ralink/Kconfig"
source "drivers/net/wireless/realtek/Kconfig"
source "drivers/net/wireless/rsi/Kconfig"
source "drivers/net/wireless/st/Kconfig"
source "drivers/net/wireless/ti/Kconfig"
source "drivers/net/wireless/zydas/Kconfig"
//根据不同的配置选择加载不同模块的配置文件
if XR829_SUDING_DRIVERS_CHOOSE
source "drivers/net/wireless/xr829/Kconfig"
endif #XR829_SUDING_DRIVERS_CHOOSE
if XR819_DRIVERS_CHOOSE
source "drivers/net/wireless/xradio/Kconfig"
endif #XR819_DRIVERS_CHOOSElichee\linux-4.9\drivers\net\wireless\Makefile
obj-$(CONFIG_BCMDHD)    += bcmdhd/
//添加如下两行
obj-$(CONFIG_XR829_SUDING_DRIVERS_CHOOSE)   += xr829/
obj-$(CONFIG_XR819_DRIVERS_CHOOSE)   += xradio/修改:
lichee\linux-4.9\drivers\net\wireless\xr829\Kconfig
menuconfig XR_WLANtristate "XRadio WLAN support"default nselect CFG80211select AVERAGEselect CRYPTOselect CRYPTO_ARC4---help---To compile this code as a module, choose M here.
if XR_WLAN
#source "drivers/net/wireless/xr/umac/Kconfig"
#source "drivers/net/wireless/xradio/wlan/Kconfig"//修改成:
source "drivers/net/wireless/xr829/umac/Kconfig"
source "drivers/net/wireless/xr829/wlan/Kconfig"
endif # XR_WLAN修改:
lichee\linux-4.9\drivers\net\wireless\xr829\Makefile
#NOSTDINC_FLAGS := -I$(srctree)/drivers/net/wireless/xradio/include/ //修改成
NOSTDINC_FLAGS := -I$(srctree)/drivers/net/wireless/xr829/include/obj-$(CONFIG_XR_WLAN) += umac/
obj-$(CONFIG_XR_WLAN) += wlan/clean-files += Module.symvers Module.markers modules modules.order在文件
lichee\linux-4.9\arch\arm\configs\sun8iw17p1_android_k23x3-wb_defconfig中添加
...........................
CONFIG_WLAN=y
CONFIG_XR829_SUDING_DRIVERS_CHOOSE=y  //添加这个配置,选择XR829的配置
CONFIG_WLAN_VENDOR_ADMTEK=y
CONFIG_WLAN_VENDOR_ATH=y
...............................

6、android平台OS的配置

android\device\softwinner\k23x3-wb\BoardConfig.mk
BOARD_WIFI_VENDOR := xradio
##BOARD_WIFI_VENDOR := QCOM
..............................
#1.4 xradio wifi config
ifeq ($(BOARD_WIFI_VENDOR), xradio)# WiFi ConfigurationWPA_SUPPLICANT_VERSION := VER_0_8_XBOARD_WPA_SUPPLICANT_DRIVER := NL80211BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_xrBOARD_HOSTAPD_DRIVER        := NL80211BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_xrBOARD_WLAN_DEVICE           := xradioWIFI_DRIVER_MODULE_PATH     := "/system/vendor/modules/xradio_wlan.ko"WIFI_DRIVER_MODULE_NAME     := "xradio_wlan"WIFI_DRIVER_MODULE_ARG      := ""include hardware/xradio/wlan/kernel-firmware/xradio-wlan.mk
endif
其它涉及到的文件:
device\softwinner\common\init.wireless.xradio.rc
android\hardware\xradio\
直接使用全志发布的公版代码即可。

以上的文件修改之后,编译整个系统,系统启动后打开WIFI基本就OK了。

二、BT部分的调试

1、android os平台部分的配置

android\device\softwinner\common\init.wireless.xradio.rc
在文件中添加:# to observe dnsmasq.leases file for dhcp information of soft ap.chown dhcp system /data/misc/dhcp#for XR829 by zhjr add#setprop persist.sys.i2s 1setprop persist.bt.sco.uart  1  //蓝牙电话走串口chmod 0666 /sys/class/bt_power/power_statechmod 0666 /sys/class/bt_power/uart_enable#end by zhaojrandroid\device\softwinner\k23x3-wb\BoardConfig.mk
修改:
BOARD_WIFI_VENDOR := xradio
##BOARD_WIFI_VENDOR := QCOM
..................................
#1.4 xradio wifi config
ifeq ($(BOARD_WIFI_VENDOR), xradio)# WiFi ConfigurationWPA_SUPPLICANT_VERSION := VER_0_8_XBOARD_WPA_SUPPLICANT_DRIVER := NL80211BOARD_WPA_SUPPLICANT_PRIVATE_LIB := lib_driver_cmd_xrBOARD_HOSTAPD_DRIVER        := NL80211BOARD_HOSTAPD_PRIVATE_LIB   := lib_driver_cmd_xrBOARD_WLAN_DEVICE           := xradioWIFI_DRIVER_MODULE_PATH     := "/system/vendor/modules/xradio_wlan.ko"WIFI_DRIVER_MODULE_NAME     := "xradio_wlan"WIFI_DRIVER_MODULE_ARG      := ""include hardware/xradio/wlan/kernel-firmware/xradio-wlan.mk
endif
其他部分已经在WIFI中配置OK.固件部分配置:
android\hardware\xradio\wlan\kernel-firmware\xradio-wlan.mk 添加:
hardware/xradio/wlan/kernel-firmware/boot_xr829.bin:$(TARGET_COPY_OUT_VENDOR)/etc/firmware/boot_xr829.bin \hardware/xradio/wlan/kernel-firmware/fw_xr829.bin:$(TARGET_COPY_OUT_VENDOR)/etc/firmware/fw_xr829.bin \hardware/xradio/wlan/kernel-firmware/sdd_xr829.bin:$(TARGET_COPY_OUT_VENDOR)/etc/firmware/sdd_xr829.bin \hardware/xradio/wlan/kernel-firmware/etf_xr829.bin:$(TARGET_COPY_OUT_VENDOR)/etc/firmware/etf_xr829.bin \hardware/xradio/wlan/kernel-firmware/fw_xr829_bt.bin:$(TARGET_COPY_OUT_VENDOR)/etc/firmware/fw_xr829_bt.bin \hardware/xradio/wlan/kernel-firmware/fw_xr829_bt_sco_hci_uart.bin:$(TARGET_COPY_OUT_VENDOR)/etc/firmware/fw_xr829_bt_sco_hci_uart.bin \hardware/xradio/wlan/kernel-firmware/fw_xr829_bt.bin:/system/etc/firmware/fw_xr829_bt.bin  \hardware/xradio/wlan/kernel-firmware/fw_xr829_bt_sco_hci_uart.bin:/system/etc/firmware/fw_xr829_bt_sco_hci_uart.bin //这个主要针对bt声音通道的固件

2、内核部分的配置修改:

lichee\linux-4.9\arch\arm\configs\sun8iw17p1_android_k23x3-wb_defconfig
添加以下配置:CONFIG_WLAN=y
CONFIG_XR829_SUDING_DRIVERS_CHOOSE=y //便于XR829的上电时序和XR829模块驱动
# CONFIG_XR819_DRIVERS_CHOOSE is not set
CONFIG_WLAN_VENDOR_ADMTEK=y
CONFIG_WLAN_VENDOR_ATH=y
# CONFIG_ATH_DEBUG is not set
# CONFIG_ATH6KL is not set
CONFIG_WLAN_VENDOR_ATMEL=y
CONFIG_WLAN_VENDOR_BROADCOM=y
# CONFIG_BRCMFMAC is not set
CONFIG_WLAN_VENDOR_CISCO=y
CONFIG_WLAN_VENDOR_INTEL=y
CONFIG_WLAN_VENDOR_INTERSIL=y
# CONFIG_HOSTAP is not set
CONFIG_WLAN_VENDOR_MARVELL=y
# CONFIG_LIBERTAS is not set
# CONFIG_MWIFIEX is not set
CONFIG_WLAN_VENDOR_MEDIATEK=y
CONFIG_WLAN_VENDOR_RALINK=y
CONFIG_WLAN_VENDOR_REALTEK=y
CONFIG_WLAN_VENDOR_RSI=y
CONFIG_WLAN_VENDOR_ST=y
CONFIG_WLAN_VENDOR_TI=y
CONFIG_WLAN_VENDOR_ZYDAS=y
# CONFIG_USB_ZD1201 is not set#CONFIG_XR_WLAN=m
#CONFIG_XRMAC=m
#CONFIG_XRMAC_RC_DEFAULT="minstrel_ht"
# CONFIG_XRMAC_RC_PID is not set
#CONFIG_XRMAC_RC_MINSTREL=y
#CONFIG_XRMAC_RC_MINSTREL_HT=y
#CONFIG_XRMAC_DEBUGFS=y
#CONFIG_XRADIO=m
#CONFIG_XRADIO_SDIO=y
#CONFIG_XRADIO_NON_POWER_OF_TWO_BLOCKSIZES=y
# CONFIG_XRADIO_USE_GPIO_IRQ is not set
#CONFIG_XRADIO_SUSPEND_POWER_OFF=y
# CONFIG_XRADIO_EXTEND_SUSPEND is not set#
# Driver debug features
#
CONFIG_XR_WLAN=m
CONFIG_XRMAC=m
CONFIG_XRMAC_RC_DEFAULT="minstrel_ht"
# CONFIG_XRMAC_RC_PID is not set
CONFIG_XRMAC_RC_MINSTREL=y
CONFIG_XRMAC_RC_MINSTREL_HT=y
CONFIG_XRMAC_DEBUGFS=y
CONFIG_XRADIO=m
CONFIG_XRADIO_SDIO=y
CONFIG_XRADIO_NON_POWER_OF_TWO_BLOCKSIZES=y
CONFIG_XRADIO_USE_GPIO_IRQ=y //走GPIO驱动
CONFIG_XRADIO_SUSPEND_POWER_OFF=y
# CONFIG_XRADIO_EXTEND_SUSPEND is not set#
# Driver debug features
#
CONFIG_XRADIO_DEBUG=y
CONFIG_XRADIO_ETF=y
# CONFIG_XRADIO_DUMP_ON_ERROR is not set
CONFIG_XRADIO_DEBUGFS=y
# CONFIG_USB_NET_RNDIS_WLAN is not set
# CONFIG_BCMDHD is not set
# CONFIG_RTL8723CS is not set
# CONFIG_RTL8723BS_VQ0 is not set

3、系统部分的配置和上电时序

3.1系统配置

lichee\tools\pack\chips\sun8iw17p1\configs\k23x3-wb\sys_config.fex
bt模块的管脚配置(请结合原理图来配置):
;--------------------------------------------------------------------------------
;bluetooth configuration
;bt_used:           0- no used, 1- used
;clocks:            external low power clock input (32.768KHz)
;bt_power:          input supply voltage
;bt_io_regulator:   bluetooth I/O voltage
;bt_rst_n:          power up/down internal regulators used by BT section
;--------------------------------------------------------------------------------
[bt]
bt_used             = 1
compatible = "allwinner,sunxi-bt"
bt_power            = "vcc-ctp"
;clocks             = 0x55
bt_rst_n            = port:PL07<1><default><default><0>
ap_wakeup_bt        = port:PL06<1><default><1><0>
音频的I2S1的PCM通道不要配置,保留速鼎模块的配置即可,最后XR829模块不用I2S1的PCM通道,走的是串口到主芯片,然后根据切源管理之后到声卡0到MCU的方式出声音(包括蓝牙电话和音乐)

3.2、上电时序

lichee\linux-4.9\drivers\misc\sunxi-rf\sunxi-bluetooth.c(跟速鼎模块共用一个上电时序)
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/rfkill.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/sunxi-gpio.h>
#include <linux/pm_runtime.h>#include "sunxi-rfkill.h"static struct sunxi_bt_platdata *bluetooth_data = NULL;
static int sunxi_bt_on(struct sunxi_bt_platdata *data, bool on_off);
static DEFINE_MUTEX(sunxi_bluetooth_mutex);static int set_bt_uart_enable(struct sunxi_bt_platdata *platdata, int enable)
{int gpio_tx = GPIOG(6);int gpio_rx = GPIOG(7);int UART_FUNC = 2;char pin_name_tx[SUNXI_PIN_NAME_MAX_LEN];char pin_name_rx[SUNXI_PIN_NAME_MAX_LEN];long unsigned int config_set;long unsigned int config_get;sunxi_gpio_to_name(gpio_tx, pin_name_tx);sunxi_gpio_to_name(gpio_rx, pin_name_rx);if (0 == enable) {config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC,SUNXI_PIN_OUTPUT_FUNC);pin_config_set(SUNXI_PINCTRL, pin_name_tx, config_set);config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0XFFFF);pin_config_get(SUNXI_PINCTRL, pin_name_tx, &config_get);if (SUNXI_PIN_OUTPUT_FUNC != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {dev_err(&platdata->pdev->dev, "[%s] set output func failed\n",pin_name_tx);return -EINVAL;} else {dev_info(&platdata->pdev->dev, "[%s] set output func success\n",pin_name_tx);}config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT,SUNXI_PIN_DATA_LOW);pin_config_set(SUNXI_PINCTRL, pin_name_tx, config_set);config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, 0XFFFF);pin_config_get(SUNXI_PINCTRL, pin_name_tx, &config_get);if (SUNXI_PIN_DATA_LOW != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {dev_err(&platdata->pdev->dev, "[%s] set output LOW failed\n",pin_name_tx);return -EINVAL;} else {dev_info(&platdata->pdev->dev, "[%s] set output LOW success\n",pin_name_tx);}config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC,SUNXI_PIN_OUTPUT_FUNC);pin_config_set(SUNXI_PINCTRL, pin_name_rx, config_set);config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0XFFFF);pin_config_get(SUNXI_PINCTRL, pin_name_rx, &config_get);if (SUNXI_PIN_OUTPUT_FUNC != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {dev_err(&platdata->pdev->dev, "[%s] set output func failed\n",pin_name_rx);return -EINVAL;} else {dev_info(&platdata->pdev->dev, "[%s] set output func success\n",pin_name_rx);}config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT,SUNXI_PIN_DATA_LOW);pin_config_set(SUNXI_PINCTRL, pin_name_rx, config_set);config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, 0XFFFF);pin_config_get(SUNXI_PINCTRL, pin_name_rx, &config_get);if (SUNXI_PIN_DATA_LOW != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {dev_err(&platdata->pdev->dev, "[%s] set output LOW failed\n",pin_name_rx);return -EINVAL;} else {dev_info(&platdata->pdev->dev, "[%s] set output LOW success\n",pin_name_rx);}} else if (1 == enable) {config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, UART_FUNC);pin_config_set(SUNXI_PINCTRL, pin_name_tx, config_set);config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0XFFFF);pin_config_get(SUNXI_PINCTRL, pin_name_tx, &config_get);if (UART_FUNC != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {dev_err(&platdata->pdev->dev, "[%s] set uart func failed\n",pin_name_tx);return -EINVAL;} else {dev_info(&platdata->pdev->dev, "[%s] set uart func success\n",pin_name_tx);}config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD,SUNXI_PIN_PULL_UP);pin_config_set(SUNXI_PINCTRL, pin_name_tx, config_set);config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, 0XFFFF);pin_config_get(SUNXI_PINCTRL, pin_name_tx, &config_get);if (SUNXI_PIN_PULL_UP != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {dev_err(&platdata->pdev->dev, "[%s] set uart pull failed\n",pin_name_tx);return -EINVAL;} else {dev_info(&platdata->pdev->dev, "[%s] set uart pull success\n",pin_name_tx);}config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, UART_FUNC);pin_config_set(SUNXI_PINCTRL, pin_name_rx, config_set);config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, 0XFFFF);pin_config_get(SUNXI_PINCTRL, pin_name_rx, &config_get);if (UART_FUNC != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {dev_err(&platdata->pdev->dev, "[%s] set uart func failed\n",pin_name_rx);return -EINVAL;} else {dev_info(&platdata->pdev->dev, "[%s] set uart func success\n",pin_name_rx);}config_set = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD,SUNXI_PIN_PULL_UP);pin_config_set(SUNXI_PINCTRL, pin_name_rx, config_set);config_get = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, 0XFFFF);pin_config_get(SUNXI_PINCTRL, pin_name_rx, &config_get);if (SUNXI_PIN_PULL_UP != SUNXI_PINCFG_UNPACK_VALUE(config_get)) {dev_err(&platdata->pdev->dev, "[%s] set uart pull failed\n",pin_name_rx);return -EINVAL;} else {dev_info(&platdata->pdev->dev, "[%s] set uart pull success\n",pin_name_rx);}}platdata->uart_enable = enable;return 0;
}static int sunxi_bt_on(struct sunxi_bt_platdata *data, bool on_off)
{struct platform_device *pdev = data->pdev;struct device *dev = &pdev->dev;int ret = 0;pr_err("%s ---sunxi_bt_on()\n", __FUNCTION__);
#if 0if (!on_off && gpio_is_valid(data->gpio_bt_rst))gpio_set_value(data->gpio_bt_rst, 0);
#endifif (data->bt_power_name) {data->bt_power = regulator_get(dev, data->bt_power_name);if (!IS_ERR(data->bt_power)) {if (on_off) {regulator_set_voltage(data->bt_power,(int)3300*1000,(int)3300*1000);ret = regulator_enable(data->bt_power);if (ret < 0) {dev_err(dev, "regulator bt_power enable failed\n");regulator_put(data->bt_power);return ret;}ret = regulator_get_voltage(data->bt_power);if (ret < 0) {dev_err(dev, "regulator bt_power get voltage failed\n");regulator_put(data->bt_power);return ret;}dev_info(dev, "check bluetooth bt_power voltage: %d\n", ret);} else {ret = regulator_disable(data->bt_power);if (ret < 0) {dev_err(dev, "regulator bt_power disable failed\n");regulator_put(data->bt_power);return ret;}}regulator_put(data->bt_power);}}#if 0if(data->io_regulator_name){data->io_regulator = regulator_get(dev, data->io_regulator_name);if (!IS_ERR(data->io_regulator)) {if (on_off) {regulator_set_voltage(data->io_regulator,(int)3300*1000,(int)3300*1000);ret = regulator_enable(data->io_regulator);if (ret < 0) {dev_err(dev, "regulator io_regulator enable failed\n");regulator_put(data->io_regulator);return ret;}ret = regulator_get_voltage(data->io_regulator);if (ret < 0) {dev_err(dev, "regulator io_regulator get voltage failed\n");regulator_put(data->io_regulator);return ret;}dev_info(dev, "check bluetooth io_regulator voltage: %d\n",ret);}else{ret = regulator_disable(data->io_regulator);if (ret < 0) {dev_err(dev, "regulator io_regulator disable failed\n");regulator_put(data->io_regulator);return ret;}}regulator_put(data->io_regulator);}}if (on_off && gpio_is_valid(data->gpio_bt_rst)) {mdelay(10);gpio_set_value(data->gpio_bt_rst, 1);}
#endifdata->power_state = on_off;return 0;
}static int sunxi_bt_set_block(void *data, bool blocked)
{struct sunxi_bt_platdata *platdata = data;struct platform_device *pdev = platdata->pdev;int ret;if (blocked != platdata->power_state) {dev_warn(&pdev->dev, "block state already is %d\n", blocked);return 0;}dev_info(&pdev->dev, "set block: %d\n", blocked);//ret = sunxi_bt_on(platdata, !blocked);//if (ret) {//  dev_err(&pdev->dev, "set block failed\n");//   return ret;//}//sunxi_wl_chipen_set(1, !blocked);return 0;
}static const struct rfkill_ops sunxi_bt_rfkill_ops = {.set_block = sunxi_bt_set_block,
};static ssize_t power_state_show(struct class *class,struct class_attribute *attr, char *buf)
{return sprintf(buf, "%d\n", bluetooth_data->power_state);
}void bt_xr829_enable(int enable);
static ssize_t power_state_store(struct class *class,struct class_attribute *attr, const char *buf, size_t count)
{unsigned long state;int err;pr_err("%s ---power_state_store()\n", __FUNCTION__);err = kstrtoul(buf, 0, &state);if (err)return err;bluetooth_data->power_state = state;pr_err("%s ---bt_xr829_enable = %ld\n",__FUNCTION__,state);if(state)bt_xr829_enable(1);elsebt_xr829_enable(0);return count;#if 0if (state > 1)return count;mutex_lock(&sunxi_bluetooth_mutex);if (state != bluetooth_data->power_state) {dev_info(&bluetooth_data->pdev->dev, "set power: %s\n", state ? "on" : "off");err = sunxi_bt_on(bluetooth_data, state);if (err) {dev_err(&bluetooth_data->pdev->dev, "set power failed\n");}}sunxi_wl_chipen_set(1, state);mutex_unlock(&sunxi_bluetooth_mutex);return count;
#endif
}static ssize_t uart_enable_store(struct class *class,struct class_attribute *attr, const char *buf, size_t count)
{unsigned long enable;int err;err = kstrtoul(buf, 0, &enable);if (err)return err;if (enable > 1)return count;pr_err("%s ---enable:%d\n", __FUNCTION__,enable);if (enable != bluetooth_data->uart_enable) {dev_info(&bluetooth_data->pdev->dev, "bt uart: %s\n", enable ? "on" : "off");err = set_bt_uart_enable(bluetooth_data, enable);if(0==err){if (0 == enable){bluetooth_data->uart_enable = 0;} else {bluetooth_data->uart_enable = 1;}}else{dev_err(&bluetooth_data->pdev->dev, "set uart failed\n");}}return count;
}static struct class_attribute bt_attribute_group[] = {__ATTR(power_state, S_IRUGO | S_IWUSR | S_IWGRP,power_state_show, power_state_store),__ATTR(uart_enable, S_IWUSR | S_IWGRP,NULL, uart_enable_store),__ATTR_NULL
};static struct class bt_power_class = {.name = "bt_power",.class_attrs = bt_attribute_group,
};
static int bt_xr829_reset = 0;
static int bt_xr829_wake = 0;
void bt_xr829_enable(int enable)
{pr_err("%s aa enable=%d\n",__FUNCTION__,enable);if(enable){gpio_direction_output(bt_xr829_reset, 1);gpio_direction_output(bt_xr829_wake, 1);}else{gpio_direction_output(bt_xr829_wake, 0);gpio_direction_output(bt_xr829_reset, 0);}
}static int sunxi_bt_probe(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node;struct device *dev = &pdev->dev;struct sunxi_bt_platdata *data;struct gpio_config config;const char *power, *io_regulator;int ret = 0;dev_info(dev, "sunxi_bt_probe()\n");data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);if (!dev)return -ENOMEM;data->pdev = pdev;bluetooth_data = data;if (of_property_read_string(np, "bt_power", &power)) {dev_warn(dev, "Missing bt_power.\n");} else {data->bt_power_name = devm_kzalloc(dev, 64, GFP_KERNEL);if (!data->bt_power_name)return -ENOMEM;elsestrcpy(data->bt_power_name,power);}dev_info(dev, "bt_power_name (%s)\n", data->bt_power_name);bt_xr829_reset = of_get_named_gpio_flags(np, "bt_rst_n", 0, (enum of_gpio_flags *)&config);if (!gpio_is_valid(bt_xr829_reset)) {pr_err("get gpio bt_rst failed\n");} else {pr_err("bt_rst gpio=%d gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",bt_xr829_reset,config.gpio,config.mul_sel,config.pull,config.drv_level,config.data);ret = devm_gpio_request(dev, bt_xr829_reset, "bt_xr829_reset");if (ret < 0) {dev_err(dev, "can't request bt_rst gpio %d\n",bt_xr829_reset);return ret;}ret = gpio_direction_output(bt_xr829_reset, 0);if (ret < 0) {dev_err(dev, "can't request output direction bt_rst gpio %d\n",bt_xr829_reset);return ret;}gpio_set_value(data->gpio_bt_rst, 0);}bt_xr829_wake = of_get_named_gpio_flags(np, "ap_wakeup_bt", 0, (enum of_gpio_flags *)&config);if (!gpio_is_valid(bt_xr829_wake)) {pr_err("get gpio bt_xr829_wake failed\n");} else {pr_err("bt_xr829_wake gpio=%d gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",bt_xr829_wake,config.gpio,config.mul_sel,config.pull,config.drv_level,config.data);ret = devm_gpio_request(dev, bt_xr829_wake, "ap_wakeup_bt");if (ret < 0) {dev_err(dev, "can't request bt_xr829_wake gpio %d\n",bt_xr829_wake);return ret;}ret = gpio_direction_output(bt_xr829_wake, 0);if (ret < 0) {dev_err(dev, "can't request output direction bt_xr829_wake %d\n",bt_xr829_wake);return ret;}}#if 0if (of_property_read_string(np, "bt_io_regulator", &io_regulator)) {dev_warn(dev, "Missing bt_io_regulator.\n");} else {data->io_regulator_name = devm_kzalloc(dev, 64, GFP_KERNEL);if (!data->io_regulator_name)return -ENOMEM;elsestrcpy(data->io_regulator_name,io_regulator);}dev_info(dev, "io_regulator_name (%s)\n", data->io_regulator_name);data->gpio_bt_rst = of_get_named_gpio_flags(np, "bt_rst_n", 0, (enum of_gpio_flags *)&config);if (!gpio_is_valid(data->gpio_bt_rst)) {dev_err(dev, "get gpio bt_rst failed\n");} else {dev_info(dev, "bt_rst gpio=%d  mul-sel=%d  pull=%d  drv_level=%d  data=%d\n",config.gpio,config.mul_sel,config.pull,config.drv_level,config.data);ret = devm_gpio_request(dev, data->gpio_bt_rst, "bt_rst");if (ret < 0) {dev_err(dev, "can't request bt_rst gpio %d\n",data->gpio_bt_rst);return ret;}ret = gpio_direction_output(data->gpio_bt_rst, 0);if (ret < 0) {dev_err(dev, "can't request output direction bt_rst gpio %d\n",data->gpio_bt_rst);return ret;}}data->lpo = devm_clk_get(dev, NULL);if (IS_ERR_OR_NULL(data->lpo)) {dev_warn(dev, "clk not config\n");} else {ret = clk_prepare_enable(data->lpo);if (ret < 0)dev_warn(dev, "can't enable clk\n");}
#endifdata->rfkill = rfkill_alloc("sunxi-bt", dev, RFKILL_TYPE_BLUETOOTH,&sunxi_bt_rfkill_ops, data);if (!data->rfkill) {ret = -ENOMEM;goto failed_alloc;}rfkill_set_states(data->rfkill, true, false);ret = rfkill_register(data->rfkill);if (ret){goto fail_rfkill;}platform_set_drvdata(pdev, data);class_register(&bt_power_class);data->power_state = 0;data->uart_enable = 1;pm_runtime_set_active(dev);pm_runtime_get(dev);pm_runtime_enable(dev);if (1 != data->power_state) {sunxi_bt_on(data, 1);}return 0;fail_rfkill:if (data->rfkill) rfkill_destroy(data->rfkill);
failed_alloc://if (!IS_ERR_OR_NULL(data->lpo)) {//   clk_disable_unprepare(data->lpo);//  clk_put(data->lpo);//}return ret;
}static int sunxi_bt_remove(struct platform_device *pdev)
{struct sunxi_bt_platdata *data = platform_get_drvdata(pdev);struct rfkill *rfk = data->rfkill;pm_runtime_disable(&pdev->dev);pm_runtime_set_suspended(&pdev->dev);class_unregister(&bt_power_class);platform_set_drvdata(pdev, NULL);if(rfk){rfkill_unregister(rfk);rfkill_destroy(rfk);}//if (!IS_ERR_OR_NULL(data->lpo)) {//   clk_disable_unprepare(data->lpo);//  clk_put(data->lpo);//}return 0;
}static int bt_pm_suspend(struct device *dev)
{struct sunxi_bt_platdata *platdata = dev_get_drvdata(dev);printk("CONFIG_PM:enter bt_pm_suspend.\n");if (pm_runtime_suspended(dev))return 0;if (platdata) {if (0 != platdata->power_state) {sunxi_bt_on(platdata, 0);}}return 0;
}static int bt_pm_resume(struct device *dev)
{struct sunxi_bt_platdata *platdata = dev_get_drvdata(dev);printk("CONFIG_PM:enter bt_pm_resume.\n");if (pm_runtime_suspended(dev))return 0;if (platdata) {if (1 != platdata->power_state) {sunxi_bt_on(platdata, 1);}}return 0;
}
static struct dev_pm_ops bt_pm_ops = {.suspend = bt_pm_suspend,.resume  = bt_pm_resume,
};static const struct of_device_id sunxi_bt_ids[] = {{ .compatible = "allwinner,sunxi-bt" },{ /* Sentinel */ }
};static struct platform_driver sunxi_bt_driver = {.probe  = sunxi_bt_probe,.remove   = sunxi_bt_remove,.driver  = {.owner  = THIS_MODULE,.name    = "sunxi-bt",.pm     = &bt_pm_ops,.of_match_table   = sunxi_bt_ids,},
};module_platform_driver(sunxi_bt_driver);MODULE_DESCRIPTION("sunxi bluetooth driver");
MODULE_LICENSE(GPL);lichee\linux-4.9\drivers\misc\sunxi-rf\sunxi-rfkill.h
/** drivers/misc/sunxi-rf/sunxi-rfkill.h** Copyright (c) 2014 softwinner.** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the* GNU General Public License for more details.**/#ifndef __SUNXI_RFKILL_H
#define __SUNXI_RFKILL_H#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/rfkill.h>struct sunxi_bt_platdata {struct regulator *bt_power;struct regulator *io_regulator;struct clk *lpo;int gpio_bt_rst;char *bt_power_name;char *io_regulator_name;int power_state;int uart_enable;struct rfkill *rfkill;struct platform_device *pdev;
};struct sunxi_wlan_platdata {int bus_index;struct regulator *wlan_power;struct regulator *wlan_power_ext;struct regulator *io_regulator;struct clk *lpo;int gpio_wlan_regon;int gpio_wlan_hostwake;int gpio_chip_en;char *wlan_power_name;char *wlan_power_ext_name;char *io_regulator_name;int power_state;int enable_state;struct platform_device *pdev;
};extern void sunxi_wl_chipen_set(int dev, int on_off);
extern void sunxi_wlan_set_power(bool on_off);
extern int  sunxi_wlan_get_bus_index(void);
extern int  sunxi_wlan_get_oob_irq(void);
extern int  sunxi_wlan_get_oob_irq_flags(void);
extern int  enable_gpio_wakeup_src(int para);
extern void sunxi_mmc_rescan_card(unsigned ids);
extern int  sunxi_get_soc_chipid(uint8_t *chipid);#endif /* SUNXI_RFKILL_H */

最后将蓝牙协议栈供应商给的gocsdk放到/system/bin下,如下:

adb push gocsdk /system/bin/
adb shell
chmod 777 /system/bin/gocsdk
sync
之后重新上电即可

系统起来之后,到蓝牙电话界面打开,手机连接车机即可,之后打开WIFI连接到路由器,进行协议栈的注册授权,之后就可以使用蓝牙音乐和蓝牙电话了,注意授权只在第一次刷机之后运行的情况,没有刷机是不需要每次都授权的。

全志XR829 WIFI和BT模块在T7 Android8.1上调试相关推荐

  1. 全志芯片 Wi-Fi/BT MAC地址定制

    问题背景 很多Wi-Fi/BT模组默认出厂是不带MAC地址的,整机厂需要根据需求,烧写特定的MAC地址. MAC地址通路 Linux-4.9后,全志平台模组MAC地址定制流程如下 系统启动后,引导程序 ...

  2. RK3288 Android5.1 RTL8723DS WIFI/BT模块移植 以及AP6XXX模块与RTL8723DS模块做兼容

    一.rk3288 android5.1 rtl8723ds移植 瑞芯微对RK3288 Android7.1的SDK已经集成了RTL8723DS的模块并做了wifi模块的兼容,但是android5.1并 ...

  3. 海华模组:WIFI、BT、SoC模组列表

    各种模块广泛应用于网络摄像头.智能机器人.儿童故事机.词典笔.智能音箱.智能家电等需要实现无线联网设备的消费类电子产品. 模块化有很大的有点:集成设计.减少调试工作,避开开发盲区.加速将产品推向市场! ...

  4. wifi android透传源代码,【终极版】ESP8266远程控制wifi透传模块带调试app

    本帖最后由 ITEAD创易工作室 于 2016-1-27 11:57 编辑 你好,2016!ITEAD给大家带来新年的第一帖!发财贴! 为什么说是发财贴呢?今天要介绍给大家的是一款成品级的wifi远程 ...

  5. GPRS、433、Wifi、Zigbee模块概念和区别

    工业数据无线传输中,常涉及到诸如GPRS.433.Wifi.Zigbee模块等这些概念,如何理解,怎么区分,可能很多人并不知道,尤其是非技术人员: 1.GPRS模块是什么?有哪些功能? GPRS DT ...

  6. 在龙芯1C单片机上使用ESP8266 wifi透传模块

    龙芯1C既可以运行linux,也可以当作单片机用.当用作linux时,可以通过USB wifi模块RTL8192C,RTL8188ETV等,当作单片机用时,可以像STM32那样使用串口透传wifi模块 ...

  7. 智能物联网有哪些应用场景?_串口WiFi模块,蓝牙模块,WiFi+蓝牙组合模块

    文章目录 前言 一.智能家居 二.智能交通 三.智慧农业 四.智能制造 五.智慧物流 六.智慧能源 七.智能医疗 八.智能安防 九.智慧建筑 十.智能零售 无线模块及应用方案 前言 物联网从萌芽到彷徨 ...

  8. 关于IMX6平台停产RL-UM02WBS-8723VAU蓝牙WiFi二合一模块升级替换参考指导

    RL-UM02WBS-8723VAU前期在IMX6平台上得到了广泛集成应用,是采用RTL8723AS-VAU开发设计的一款高性能2.4G单频单通道USB接口的蓝牙WiFi二合一模块,有USB+PCM接 ...

  9. USB WiFi 模组/模块介绍

    USB WiFi 模组/模块介绍 USB 通用串行总线 (Universal Serial Bus,USB) 是一种新兴的并逐渐取代其他接口标准的数据通信方式,由 Intel.Compaq.Digit ...

最新文章

  1. 1103 Integer Factorization 需再做
  2. ssm查询一条数据并显示_高亮显示查询数据,其实很简单
  3. Devstack单节点环境实战配置
  4. Centos6.5下配置DNS服务器
  5. 【Linux sshfs】sshfs将远程目录挂载到本地目录
  6. java小程序小游戏代码贪吃蛇,附高频面试题合集
  7. ASP.NET Core文件上传、下载与删除
  8. 湖南工业大学在线计算机作业答案,湖南工业大学《计算机组成原理》试题集,共7份,有部分答案...
  9. linux搭建oracle脚本,Linux脚本自动安装Oracle
  10. CV新赛事 | 水下鱼类物种识别
  11. Python检测U盘插入、自动复制文件并写入新文件
  12. Linux学习笔记004----CentOS7 提升普通用户权限到Root权限
  13. 深入理解异步I/O+epoll+协程
  14. 安装oracle 12c遇到问题
  15. 电子工程师名片——FAT16文件系统(转)
  16. ios7 获取UITablleViewCell
  17. C语言程序设计经典例题(考研必背)(基础篇)第二周
  18. 闲谈绩效考核——来自项目管理群的讨论
  19. c语言与编程语言的区别,C语言与其他编程语言的区别
  20. 加快SP3下载速度并使用第三方系统主题!适用于XP SP3的TCPIP连接数与主题破解增强补丁下载...

热门文章

  1. sqlserver Sum求和float类型 数据不准问题
  2. 第五代选择器Icarus
  3. python逆序输出_python倒序输出
  4. linux clk驱动框架
  5. 梯度与Roberts、Prewitt、Sobel、Lapacian算子
  6. Logistic Regression 逻辑斯蒂回归
  7. Java并发编程-Exchange
  8. shell-awk命令详解
  9. 梅林安装opkg后安装iperf3_路由器最高速度/性能测试 - Windows 安装 IPerf3 及 使用方法...
  10. python元组和列表逆序_Python容器:列表与元组