btfmcodec: Add btadv audio support

This change adds below support for BT advance audio
* Add support for codec type mixer control
* Update slim driver to read master id, channel number.
* Update slim driver to support HW EP.
* Add support for transport switch based on the request

CRs-Fixed: 3298745
Change-Id: Ica349cb6f3615f4dc51bbc3070c90d43eeba1cdd
This commit is contained in:
Balakrishna Godavarthi
2023-01-02 12:06:09 +05:30
parent 30209d05c3
commit 4a2649332e
13 changed files with 1276 additions and 156 deletions

View File

@@ -5,4 +5,4 @@ bt_fm_slim-objs := btfm_slim.o btfm_slim_codec.o btfm_slim_slave.o
obj-$(CONFIG_BTFM_SLIM) += bt_fm_slim.o
# Below src is for BTFM Driver support based on btfm codec
btfm_slim_codec-objs := btfm_slim.o btfm_slim_hw_interface.o btfm_slim_slave.o
obj-$(CONFIG_SLIM_BTFM_CODEC) += btfm_slim_codec.o
obj-$(CONFIG_SLIM_BTFM_CODEC) += btfm_slim_codec.o

View File

@@ -515,6 +515,67 @@ int btfm_slim_hw_deinit(struct btfmslim *btfmslim)
return ret;
}
#if IS_ENABLED (CONFIG_BTFM_SLIM)
void btfm_slim_get_hwep_details(struct slim_device *dev, struct btfmslim *btfm_slim)
{
}
#else
void btfm_slim_get_hwep_details(struct slim_device *slim, struct btfmslim *btfm_slim)
{
struct device_node *np = slim->dev.of_node;
const __be32 *prop;
struct btfmslim_ch *rx_chs = btfm_slim->rx_chs;
struct btfmslim_ch *tx_chs = btfm_slim->tx_chs;
int len;
prop = of_get_property(np, "qcom,btslim-address", &len);
if (prop) {
btfm_slim->device_id = be32_to_cpup(&prop[0]);
BTFMSLIM_DBG("hwep slim address define in dt %08x", btfm_slim->device_id);
} else {
BTFMSLIM_ERR("btslim-address is not defined in dt using default address");
btfm_slim->device_id = 0;
}
if (!rx_chs || !tx_chs) {
BTFMSLIM_ERR("either rx/tx channels are configured to null");
return;
}
prop = of_get_property(np, "qcom,btslimrx-channels", &len);
if (prop) {
/* Check if we need any protection for index */
rx_chs[0].ch = (uint8_t)be32_to_cpup(&prop[0]);
rx_chs[1].ch = (uint8_t)be32_to_cpup(&prop[1]);
BTFMSLIM_DBG("Rx: id\tname\tport\tch");
BTFMSLIM_DBG(" %d\t%s\t%d\t%d", rx_chs[0].id,
rx_chs[0].name, rx_chs[0].port,
rx_chs[0].ch);
BTFMSLIM_DBG(" %d\t%s\t%d\t%d", rx_chs[1].id,
rx_chs[1].name, rx_chs[1].port,
rx_chs[1].ch);
} else {
BTFMSLIM_ERR("btslimrx channels are missing in dt using default values");
}
prop = of_get_property(np, "qcom,btslimtx-channels", &len);
if (prop) {
/* Check if we need any protection for index */
tx_chs[0].ch = (uint8_t)be32_to_cpup(&prop[0]);
tx_chs[1].ch = (uint8_t)be32_to_cpup(&prop[1]);
BTFMSLIM_DBG("Tx: id\tname\tport\tch");
BTFMSLIM_DBG(" %d\t%s\t%d\t%x", tx_chs[0].id,
tx_chs[0].name, tx_chs[0].port,
tx_chs[0].ch);
BTFMSLIM_DBG(" %d\t%s\t%d\t%x", tx_chs[1].id,
tx_chs[1].name, tx_chs[1].port,
tx_chs[1].ch);
} else {
BTFMSLIM_ERR("btslimtx channels are missing in dt using default values");
}
}
#endif
static int btfm_slim_status(struct slim_device *sdev,
enum slim_device_status status)
{
@@ -526,6 +587,7 @@ static int btfm_slim_status(struct slim_device *sdev,
#if IS_ENABLED(CONFIG_BTFM_SLIM)
ret = btfm_slim_register_codec(btfm_slim);
#else
btfm_slim_get_hwep_details(sdev, btfm_slim);
ret = btfm_slim_register_hw_ep(btfm_slim);
#endif
if (ret)

View File

@@ -73,6 +73,9 @@ struct btfmslim {
int (*vendor_init)(struct btfmslim *btfmslim);
int (*vendor_port_en)(struct btfmslim *btfmslim, uint8_t port_num,
uint8_t rxport, uint8_t enable);
#if IS_ENABLED(CONFIG_SLIM_BTFM_CODEC)
int device_id;
#endif
};
extern int btfm_feedback_ch_setting;

View File

@@ -26,15 +26,16 @@
static int bt_soc_enable_status;
int btfm_feedback_ch_setting;
static uint8_t usecase_codec;
static int btfm_slim_codec_write(struct snd_soc_component *codec,
static int btfm_slim_hwep_write(struct snd_soc_component *codec,
unsigned int reg, unsigned int value)
{
BTFMSLIM_DBG("");
return 0;
}
static unsigned int btfm_slim_codec_read(struct snd_soc_component *codec,
static unsigned int btfm_slim_hwep_read(struct snd_soc_component *codec,
unsigned int reg)
{
BTFMSLIM_DBG("");
@@ -72,25 +73,39 @@ static int btfm_put_feedback_ch_setting(struct snd_kcontrol *kcontrol,
return 1;
}
static const struct snd_kcontrol_new status_controls[] = {
static int btfm_get_codec_type(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
BTFMSLIM_DBG("current codec type:%s", codec_text[usecase_codec]);
ucontrol->value.integer.value[0] = usecase_codec;
return 1;
}
static int btfm_put_codec_type(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
usecase_codec = ucontrol->value.integer.value[0];
BTFMSLIM_DBG("codec type set to:%s", codec_text[usecase_codec]);
return 1;
}
static struct snd_kcontrol_new status_controls[] = {
SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0,
btfm_soc_status_get,
btfm_soc_status_put),
btfm_soc_status_get, btfm_soc_status_put),
SOC_SINGLE_EXT("BT set feedback channel", 0, 0, 1, 0,
btfm_get_feedback_ch_setting,
btfm_put_feedback_ch_setting)
btfm_put_feedback_ch_setting),
SOC_ENUM_EXT("BT codec type", codec_display,
btfm_get_codec_type, btfm_put_codec_type),
};
static int btfm_slim_codec_probe(struct snd_soc_component *codec)
static int btfm_slim_hwep_probe(struct snd_soc_component *codec)
{
BTFMSLIM_DBG("");
snd_soc_add_component_controls(codec, status_controls,
ARRAY_SIZE(status_controls));
return 0;
}
static void btfm_slim_codec_remove(struct snd_soc_component *codec)
static void btfm_slim_hwep_remove(struct snd_soc_component *codec)
{
BTFMSLIM_DBG("");
}
@@ -163,6 +178,30 @@ static int btfm_slim_dai_hw_params(void *dai, uint32_t bps,
return 0;
}
void btfm_get_sampling_rate(uint32_t *sampling_rate)
{
uint8_t codec_types_avb = ARRAY_SIZE(codec_text);
if (usecase_codec > (codec_types_avb - 1)) {
BTFMSLIM_ERR("falling back to use default sampling_rate: %u",
*sampling_rate);
return;
}
if (*sampling_rate == 44100 || *sampling_rate == 48000) {
if (usecase_codec == LDAC ||
usecase_codec == APTX_AD)
*sampling_rate = (*sampling_rate) *2;
}
if (usecase_codec == LC3_VOICE ||
usecase_codec == APTX_AD_SPEECH ||
usecase_codec == LC3 || usecase_codec == APTX_AD_QLEA) {
*sampling_rate = 96000;
}
BTFMSLIM_INFO("current usecase codec type %s and sampling rate:%u khz",
codec_text[usecase_codec], *sampling_rate);
}
static int btfm_slim_dai_prepare(void *dai, uint32_t sampling_rate, uint32_t direction, int id)
{
struct hwep_data *hwep_info = (struct hwep_data *)dai;
@@ -175,6 +214,7 @@ static int btfm_slim_dai_prepare(void *dai, uint32_t sampling_rate, uint32_t dir
btfmslim->direction = direction;
bt_soc_enable_status = 0;
btfm_get_sampling_rate(&sampling_rate);
/* save sample rate */
btfmslim->sample_rate = sampling_rate;
@@ -254,7 +294,7 @@ static int btfm_slim_dai_set_channel_map(void *dai,
* get channel handler from slimbus driver
*/
rx_chs->ch = *(uint8_t *)(rx_slot + i);
BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", rx_chs->id,
BTFMSLIM_DBG(" %d\t%s\t%d\t%x", rx_chs->id,
rx_chs->name, rx_chs->port, rx_chs->ch);
}
@@ -265,7 +305,7 @@ static int btfm_slim_dai_set_channel_map(void *dai,
* get channel handler from slimbus driver
*/
tx_chs->ch = *(uint8_t *)(tx_slot + i);
BTFMSLIM_DBG(" %d\t%s\t%d\t%x\t%d\t%x", tx_chs->id,
BTFMSLIM_DBG(" %d\t%s\t%d\t%x", tx_chs->id,
tx_chs->name, tx_chs->port, tx_chs->ch);
}
@@ -352,6 +392,45 @@ static int btfm_slim_dai_get_channel_map(void *dai,
return 0;
}
int btfm_slim_dai_get_configs (void * dai,
struct master_hwep_configurations *hwep_config,
uint8_t id)
{
struct hwep_data *hwep_info = (struct hwep_data *)dai;
struct btfmslim *btfmslim = dev_get_drvdata(hwep_info->dev);
struct btfmslim_ch *ch = NULL;
int i = 0;
BTFMSLIM_DBG("");
hwep_config->stream_id = id;
hwep_config->device_id = btfmslim->device_id;
hwep_config->sample_rate = btfmslim->sample_rate;
hwep_config->bit_width = (uint8_t)btfmslim->bps;
hwep_config->codectype = usecase_codec;
hwep_config->direction = btfmslim->direction;
switch (id) {
case BTFM_FM_SLIM_TX:
case BTFM_BT_SCO_SLIM_TX:
ch = btfmslim->tx_chs;
break;
case BTFM_BT_SCO_A2DP_SLIM_RX:
case BTFM_BT_SPLIT_A2DP_SLIM_RX:
ch = btfmslim->rx_chs;
break;
}
for (; i < id ; i++) {
if (ch[i].id == id) {
BTFMSLIM_DBG("id matched");
hwep_config->num_channels = 1;
hwep_config->chan_num = ch[i].ch;
break;
}
}
return 1;
}
static struct hwep_dai_ops btfmslim_hw_dai_ops = {
.hwep_startup = btfm_slim_dai_startup,
.hwep_shutdown = btfm_slim_dai_shutdown,
@@ -359,6 +438,8 @@ static struct hwep_dai_ops btfmslim_hw_dai_ops = {
.hwep_prepare = btfm_slim_dai_prepare,
.hwep_set_channel_map = btfm_slim_dai_set_channel_map,
.hwep_get_channel_map = btfm_slim_dai_get_channel_map,
.hwep_get_configs = btfm_slim_dai_get_configs,
.hwep_codectype = &usecase_codec,
};
static struct hwep_dai_driver btfmslim_dai_driver[] = {
@@ -403,10 +484,10 @@ static struct hwep_dai_driver btfmslim_dai_driver[] = {
};
static struct hwep_comp_drv btfmslim_hw_driver = {
.hwep_probe = btfm_slim_codec_probe,
.hwep_remove = btfm_slim_codec_remove,
.hwep_read = btfm_slim_codec_read,
.hwep_write = btfm_slim_codec_write,
.hwep_probe = btfm_slim_hwep_probe,
.hwep_remove = btfm_slim_hwep_remove,
.hwep_read = btfm_slim_hwep_read,
.hwep_write = btfm_slim_hwep_write,
};
int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim)
@@ -431,6 +512,8 @@ int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim)
hwep_info->dai_drv = btfmslim_dai_driver;
hwep_info->num_dai = ARRAY_SIZE(btfmslim_dai_driver);
hwep_info->num_dai = 2;
hwep_info->num_mixer_ctrl = ARRAY_SIZE(status_controls);
hwep_info->mixer_ctrl = status_controls;
set_bit(BTADV_AUDIO_MASTER_CONFIG, &hwep_info->flags);
/* Register to hardware endpoint */
ret = btfmcodec_register_hw_ep(hwep_info);

View File

@@ -15,4 +15,28 @@
// Todo protect with flags
int btfm_slim_register_hw_ep(struct btfmslim *btfm_slim);
void btfm_slim_unregister_hwep(void);
typedef enum Codec {
SBC = 0,
AAC,
LDAC,
APTX,
APTX_HD,
APTX_AD,
LC3,
APTX_AD_SPEECH,
LC3_VOICE,
APTX_AD_QLEA,
APTX_AD_R4,
NO_CODEC
} codectype;
static char const *codec_text[] = {"CODEC_TYPE_SBC", "CODEC_TYPE_AAC",
"CODEC_TYPE_LDAC", "CODEC_TYPE_APTX",
"CODEC_TYPE_APTX_HD", "CODEC_TYPE_APTX_AD",
"CODEC_TYPE_LC3", "CODEC_TYPE_APTX_AD_SPEECH",
"CODEC_TYPE_LC3_VOICE", "CODEC_TYPE_APTX_AD_QLEA",
"CODEC_TYPE_APTX_AD_R4","CODEC_TYPE_INVALID"};
static SOC_ENUM_SINGLE_EXT_DECL(codec_display, codec_text);
#endif /*__LINUX_BTFM_SLIM_HW_INTERFACE_H*/