全志平台速鼎模块的BT调试记录
全志平台速鼎模块的BT调试记录
1、电路原理:
2、需要配置的接口
控制管脚:
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、上电时序,需要对控制空间和串口流控进行操作,具体如下:
lichee\linux-4.9\drivers\misc\sunxi-rf\sunxi-bluetooth.c
//以下代码是linux4.9 android8.x的代码,满足开机打开电源,上层Open时打开使能,close时关闭使能。
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;
};
#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) { //bt_powerdata->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);
//主要由这个函数在上层调用/sys/class/bt_power/power_state接口,1:使能 0:不使能
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); //AP_WAKE_BT<---->PL06和BT_LDO_EN<----->PL07同时打开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;}}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; //power_state为0,不使能data->uart_enable = 1; //UART口OK,状态为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);//BT的管脚系统配置
tools\pack\chips\sun8iw17p1\configs\k23x3-wb\sys_config.fex
;--------------------------------------------------------------------------------
;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" //cldo1 vcc-ctp
;clocks = 0x55
bt_rst_n = port:PL07<1><default><default><0> //BT_LDO_EN<----->PL07
ap_wakeup_bt = port:PL06<1><default><1><0> //AP_WAKE_BT<---->PL06
4、UART口和PCM通道的系统管脚和模式配置:
lichee\tools\pack\chips\sun8iw17p1\configs\k23x3-wb\sys_config.fex
...............
[uart1]
uart1_used = 1 //这里必须设置成1
uart1_port = 1
uart1_type = 2
uart1_tx = port:PG06<2><1><default><default>
uart1_rx = port:PG07<2><1><default><default>
uart1_rts = port:PG08<2><1><default><default>
uart1_cts = port:PG09<2><1><default><default>
[uart1_suspend]
uart1_tx = port:PG06<7><1><default><default>
uart1_rx = port:PG07<7><1><default><default>
uart1_rts = port:PG08<7><1><default><default>
uart1_cts = port:PG09<7><1><default><default>
..............
;--------------------------------------------------------------------------------
; NOTE :Make sure daudio1mach_used = 0x1,daudio1_used = 0x1,
; if register the sound card DAUDIO1.
;--------------------------------------------------------------------------------
;--------------------------------------------------------------------------------
;allwinner,pcm_lrck_period :16/32/64/128/256
;allwinner,pcm_lrckr_period :no use
;allwinner,slot_width_select :16bits/20bits/24bits/32bits
;allwinner,pcm_lsb_first :0: msb first; 1: lsb first
;allwinner,tx_data_mode :0: 16bit linear PCM; 1: 8bit linear PCM; 2: 8bit u-law; 3: 8bit a-law
;allwinner,rx_data_mode :0: 16bit linear PCM; 1: 8bit linear PCM; 2: 8bit u-law; 3: 8bit a-law
;allwinner,daudio_master :1: SND_SOC_DAIFMT_CBM_CFM(codec clk & FRM master) use
; 2: SND_SOC_DAIFMT_CBS_CFM(codec clk slave & FRM master) not use
; 3: SND_SOC_DAIFMT_CBM_CFS(codec clk master & frame slave) not use
; 4: SND_SOC_DAIFMT_CBS_CFS(codec clk & FRM slave) use
;allwinner,audio_format: 1:SND_SOC_DAIFMT_I2S(standard i2s format). use
; 2:SND_SOC_DAIFMT_RIGHT_J(right justfied format).
; 3:SND_SOC_DAIFMT_LEFT_J(left justfied format)
; 4:SND_SOC_DAIFMT_DSP_A(pcm. MSB is available on 2nd BCLK rising edge after LRC rising edge). use
; 5:SND_SOC_DAIFMT_DSP_B(pcm. MSB is available on 1nd BCLK rising edge after LRC rising edge)
;allwinner,signal_inversion:1:SND_SOC_DAIFMT_NB_NF(normal bit clock + frame) use
; 2:SND_SOC_DAIFMT_NB_IF(normal BCLK + inv FRM)
; 3:SND_SOC_DAIFMT_IB_NF(invert BCLK + nor FRM) use
; 4:SND_SOC_DAIFMT_IB_IF(invert BCLK + FRM)
;allwinner,frametype :0: short frame = 1 clock width; 1: long frame = 2 clock width
;allwinner,tdm_config :0:pcm 1:i2s
;allwinner,mclk_div :0: not output(normal setting this) 1/2/4/6/8/12/16/24/32/48/64/96/128/176/192:
; setting mclk as input clock to external codec, freq is pll_audio/mclk_div
;allwinner,daudio0_used :0:not use 1:use
;-------------------------------------------------------------------------------
; NOTE :Make sure daudio0mach_used = 0x1,daudio0_used = 0x1,
; if register the sound card DAUDIO0.
;--------------------------------------------------------------------------------
[snddaudio1]
snddaudio1_used = 1
;-----------------------------------------------------------------------------
[daudio1]
;pcm_lrck_period = 0x20
pcm_lrck_period = 0x40
pcm_lrckr_period = 0x01
slot_width_select = 0x10
pcm_lsb_first = 0x0
tx_data_mode = 0x0
rx_data_mode = 0x0
;daudio_master = 0x04
;audio_format = 0x01
;signal_inversion = 0x01
daudio_master = 0x01
audio_format = 0x04
signal_inversion = 0x02
frametype = 0x0
;tdm_config = 0x01
tdm_config = 0x00
mclk_div = 0x0
;daudio1_used = 0
daudio1_used = 1 //这里一定要配置成1
//以上参数请参考BT模组中PCM输出的时序
5、修改上层访问的设备节点的权限和添加固件
android\device\softwinner\common\init.wireless.qcom.rc
在文件中添加:
......................
# to observe dnsmasq.leases file for dhcp information of soft ap.chown dhcp system /data/misc/dhcpchmod 0666 /sys/class/bt_power/power_state //添加权限
android\device\softwinner\t7-common\ueventd.sun8iw17p1.rc
............................
/dev/ttyS* 0666 system system
我们使用UART1接口连接蓝牙,使用/dev/ttyS1设备节点添加固件:
需要将以下固件文件拷贝到/system/etc/firmware/目录中
android\device\softwinner\k23x3-wb\hardware\bt\firmware\nvm_tlv_3.2.bin
android\device\softwinner\k23x3-wb\hardware\bt\firmware\rampatch_tlv_3.2.tlv
android\device\softwinner\k23x3-wb\hardware\bt\firmware\rampatch_tlv_3.2.tlv
android\device\softwinner\k23x3-wb\hardware\bt\firmware\rampatch_tlv_tf_1.1.tlv
修改:
android\device\softwinner\k23x3-wb\k23x3_wb.mk
# BT
PRODUCT_COPY_FILES += \ $(PRODUCT_DEVICE_PATH)/hardware/bt/firmware/nvm_tlv_3.2.bin:/system/etc/firmware/nvm_tlv_3.2.bin \ $(PRODUCT_DEVICE_PATH)/hardware/bt/firmware/rampatch_tlv_3.2.tlv:/system/etc/firmware/rampatch_tlv_3.2.tlv \ $(PRODUCT_DEVICE_PATH)/hardware/bt/firmware/nvm_tlv_tf_1.1.bin:/system/etc/firmware/nvm_tlv_tf_1.1.bin \ $(PRODUCT_DEVICE_PATH)/hardware/bt/firmware/rampatch_tlv_tf_1.1.tlv:/system/etc/firmware/rampatch_tlv_tf_1.1.tlv \
以上的信息配置OK,之后。直接找模组供应商,要协议栈的相关程序,因为模组用于车载项目,不能使用Android自带的framework层部分,直接使用BT模块的CHI模式,不是CMD模式,如果使用CMD模式,直接跟模组发AT指令即可,如果使用chi模式,需要模组厂家或第第三方给出协议栈的相关文件,具体跟APP有关,到这个步骤,OS层面就OK了。而通过跟速鼎调试来看,速鼎将提供:
system/bin/gocsdk
system/etc/firmware/nvm_tlv_tf_1.1.bin
system/etc/firmware/rampatch_tlv_tf_1.1.tlv
system/config_具体公司.ini //不同厂家内容可能不同
其中system/bin/gocsdk文件将在系统启动的时候用服务进行加载,将使能 BT模块,打开/dev/ttyS1,打开PCM通道,同时处理蓝牙连接,播放音乐,打电话,同步电话本等操作,主要是协议栈的处理。
系统启动加载的蓝牙服务
android\device\softwinner\k23x3-wb\init.device.rc
service gocsdk /system/bin/gocsdk /dev/ttyS1 500000 //这个主要是供应商给的协议栈等class mainuser rootgroup rootservice gocsdk_be130 /system/bin/gocsdk_be130 /dev/ttyS1 500000class mainuser rootgroup rootdisabled
将以上文件导入到系统中对应目录之后,重启系统,然后基本就可以连接手机,打电话、播放音乐了。