Add support for BT/FM SoundWire slave driver

Added support for BT/FM SoundWire slave driver.
The driver registers as a codec driver with ALSA.
Slave port configuration is sent to master driver.
Master driver takes care of programming master and
slave registers at once when BT audio usecase is
started/stopped.

Change-Id: I3a4de9872323c470f2ec73218601be94a768d726
Signed-off-by: Satish Kumar Kodishala <quic_skodisha@quicinc.com>
This commit is contained in:
Satish Kumar Kodishala
2023-09-25 12:24:01 +05:30
orang tua d1e8e16be6
melakukan d638487f10
7 mengubah file dengan 836 tambahan dan 0 penghapusan

12
soundwire/Kconfig Normal file
Melihat File

@@ -0,0 +1,12 @@
config BTFM_SWR
tristate "MSM Bluetooth/FM SoundWire Device"
depends on MSM_BT_POWER
help
This enables BT/FM soundwire driver to open/close ports.
This will make use of soundwire bus driver and soundwire
master driver to communicate with soundwire slave.
Say Y here to compile support for Bluetooth/FM soundwire slave driver
into the kernel or say M to compile as a module.

3
soundwire/Makefile Normal file
Melihat File

@@ -0,0 +1,3 @@
ccflags-y += -I$(BT_ROOT)/include
bt_fm_swr-objs := btfm_swr.o btfm_swr_codec.o btfm_swr_slave.o
obj-$(CONFIG_BTFM_SWR) += bt_fm_swr.o

288
soundwire/btfm_swr.c Normal file
Melihat File

@@ -0,0 +1,288 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/debugfs.h>
#include <linux/ratelimit.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include "btpower.h"
#include "btfm_swr.h"
#include "btfm_swr_slave.h"
struct class *btfm_swr_class;
static int btfm_swr_major;
struct btfmswr *pbtfmswr;
static int btfm_num_ports_open;
#define BT_CMD_SWR_TEST 0xbfac
static int btfm_swr_probe(struct swr_device *pdev);
int btfm_get_bt_soc_index(int chipset_ver)
{
switch (chipset_ver) {
case QCA_GANGES_SOC_ID_0100:
case QCA_GANGES_SOC_ID_0200:
return GANGES;
case QCA_EVROS_SOC_ID_0100:
case QCA_EVROS_SOC_ID_0200:
return EVROS;
default:
BTFMSWR_ERR("no BT SOC id defined, returning EVROS");
return EVROS;
}
}
int btfm_swr_hw_init(void)
{
uint8_t dev_num = 0;
int ret = 0;
int chipset_ver;
BTFMSWR_DBG("");
if (pbtfmswr->initialized)
BTFMSWR_INFO("Already initialized");
// get BT chipset version
chipset_ver = btpower_get_chipset_version();
// get BT/FM SOC slave port details
pbtfmswr->soc_index = btfm_get_bt_soc_index(chipset_ver);
BTFMSWR_INFO("chipset soc version:%x, soc index: %x", chipset_ver,
pbtfmswr->soc_index);
pbtfmswr->p_dai_port = &slave_port[pbtfmswr->soc_index];
// get logical address
/*
* Add 5msec delay to provide sufficient time for
* soundwire auto enumeration of slave devices as
* per HW requirement.
*/
usleep_range(5000, 5010);
ret = swr_get_logical_dev_num(pbtfmswr->swr_slave, pbtfmswr->p_dai_port->ea,
&dev_num);
if (ret) {
BTFMSWR_ERR("error while getting logical device number");
goto err;
}
pbtfmswr->swr_slave->dev_num = dev_num;
pbtfmswr->initialized = true;
err:
return ret;
}
int btfm_swr_enable_port(u8 port_num, u8 ch_count, u32 sample_rate, u8 usecase)
{
int ret = 0;
u8 port_id[MAX_BT_PORTS];
u8 num_ch[MAX_BT_PORTS];
u8 ch_mask[MAX_BT_PORTS];
u32 ch_rate[MAX_BT_PORTS];
u8 port_type[MAX_BT_PORTS];
u8 num_port = 1;
// master expects port num -1 to be sent
port_id[0] = port_num-1;
num_ch[0] = ch_count;
ch_mask[0] = ch_count == 2 ? TWO_CHANNEL_MASK : ONE_CHANNEL_MASK;
ch_rate[0] = sample_rate;
port_type[0] = usecase;
BTFMSWR_INFO("enabling port : %d\n", port_num);
ret = swr_connect_port(pbtfmswr->swr_slave, &port_id[0], num_port,
&ch_mask[0], &ch_rate[0], &num_ch[0],
&port_type[0]);
if (ret < 0) {
BTFMSWR_ERR("swr_connect_port failed, error %d", ret);
return ret;
}
BTFMSWR_INFO("calling swr_slvdev_datapath_control\n");
ret = swr_slvdev_datapath_control(pbtfmswr->swr_slave,
pbtfmswr->swr_slave->dev_num,
true);
if (ret < 0)
BTFMSWR_ERR("swr_slvdev_datapath_control failed");
if (ret == 0)
btfm_num_ports_open++;
BTFMSWR_INFO("btfm_num_ports_open: %d", btfm_num_ports_open);
return ret;
}
int btfm_swr_disable_port(u8 port_num, u8 ch_count, u8 usecase)
{
int ret = 0;
u8 port_id[MAX_BT_PORTS];
u8 ch_mask[MAX_BT_PORTS];
u8 port_type[MAX_BT_PORTS];
u8 num_port = 1;
// master expects port num -1 to be sent
port_id[0] = port_num-1;
ch_mask[0] = ch_count == 2 ? TWO_CHANNEL_MASK : ONE_CHANNEL_MASK;
port_type[0] = usecase;
BTFMSWR_INFO("disabling port : %d\n", port_num);
ret = swr_disconnect_port(pbtfmswr->swr_slave, &port_id[0], num_port,
&ch_mask[0], &port_type[0]);
if (ret < 0)
BTFMSWR_ERR("swr_disconnect_port port failed, error %d", ret);
BTFMSWR_INFO("calling swr_slvdev_datapath_control\n");
ret = swr_slvdev_datapath_control(pbtfmswr->swr_slave,
pbtfmswr->swr_slave->dev_num,
false);
if (ret < 0)
BTFMSWR_ERR("swr_slvdev_datapath_control failed");
if (btfm_num_ports_open > 0)
btfm_num_ports_open--;
BTFMSWR_INFO("btfm_num_ports_open: %d", btfm_num_ports_open);
return ret;
}
static long btfm_swr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int ret = 0;
BTFMSWR_INFO("");
switch (cmd) {
case BT_CMD_SWR_TEST:
BTFMSWR_INFO("cmd BT_CMD_SLIM_TEST, call btfm_swr_hw_init");
ret = btfm_swr_hw_init();
break;
}
return ret;
}
static const struct file_operations bt_dev_fops = {
.unlocked_ioctl = btfm_swr_ioctl,
.compat_ioctl = btfm_swr_ioctl,
};
static int btfm_swr_probe(struct swr_device *pdev)
{
int ret = 0;
BTFMSWR_INFO("");
pbtfmswr = devm_kzalloc(&pdev->dev,
sizeof(struct btfmswr), GFP_KERNEL);
if (!pbtfmswr) {
BTFMSWR_ERR("memory allocation to driver failed");
return -ENOMEM;
}
swr_set_dev_data(pdev, pbtfmswr);
pbtfmswr->swr_slave = pdev;
pbtfmswr->dev = &pdev->dev;
pbtfmswr->initialized = false;
// register with ALSA
ret = btfm_swr_register_codec(pbtfmswr);
if (ret) {
BTFMSWR_ERR("registration with ALSA failed, returning");
goto dealloc;
}
btfm_swr_major = register_chrdev(0, "btfm_swr", &bt_dev_fops);
if (btfm_swr_major < 0) {
BTFMSWR_ERR("%s: failed to allocate char dev\n", __func__);
ret = -1;
goto register_err;
}
btfm_swr_class = class_create(THIS_MODULE, "btfmswr-dev");
if (IS_ERR(btfm_swr_class)) {
BTFMSWR_ERR("%s: coudn't create class\n", __func__);
ret = -1;
goto class_err;
}
if (device_create(btfm_swr_class, NULL, MKDEV(btfm_swr_major, 0),
NULL, "btfmswr") == NULL) {
BTFMSWR_ERR("%s: failed to allocate char dev\n", __func__);
ret = -1;
goto device_err;
}
return ret;
device_err:
class_destroy(btfm_swr_class);
class_err:
unregister_chrdev(btfm_swr_major, "btfm_swr");
register_err:
btfm_swr_unregister_codec(pbtfmswr->dev);
dealloc:
kfree(pbtfmswr);
return ret;
}
static const struct swr_device_id btfm_swr_id[] = {
{SWR_SLAVE_COMPATIBLE_STR, 0},
{}
};
static const struct of_device_id btfm_swr_dt_match[] = {
{
.compatible = "qcom,btfmswr_slave",
},
{}
};
static struct swr_driver btfm_swr_driver = {
.driver = {
.name = "btfmswr-driver",
.owner = THIS_MODULE,
.of_match_table = btfm_swr_dt_match,
},
.probe = btfm_swr_probe,
.id_table = btfm_swr_id,
};
static int __init btfm_swr_init(void)
{
BTFMSWR_INFO("");
return swr_driver_register(&btfm_swr_driver);
}
static void __exit btfm_swr_exit(void)
{
BTFMSWR_INFO("");
swr_driver_unregister(&btfm_swr_driver);
}
module_init(btfm_swr_init);
module_exit(btfm_swr_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("BTFM SoundWire Slave driver");

103
soundwire/btfm_swr.h Normal file
Melihat File

@@ -0,0 +1,103 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef BTFM_SWR_H
#define BTFM_SWR_H
#include <linux/types.h>
#include <linux/mutex.h>
#include <bindings/audio-codec-port-types.h>
#include "soc/soundwire.h"
#define SWR_SLAVE_COMPATIBLE_STR "btfmswr_slave"
#define BTFMSWR_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
#define BTFMSWR_INFO(fmt, arg...) pr_info("%s: " fmt "\n", __func__, ## arg)
#define BTFMSWR_ERR(fmt, arg...) pr_err("%s: " fmt "\n", __func__, ## arg)
extern struct btfmswr *pbtfmswr;
// assumption is that we use adjacent channels
#define ONE_CHANNEL_MASK 1
#define TWO_CHANNEL_MASK 3
#define MAX_BT_PORTS 1
/* Codec driver defines */
enum {
FMAUDIO_TX = 0,
BTAUDIO_TX,
BTAUDIO_RX,
BTAUDIO_A2DP_SINK_TX,
BTFM_NUM_CODEC_DAIS
};
enum {
EVROS = 0,
GANGES = 1,
MAX_SOC_ID = 0xFF
};
struct btfmswr_dai_port_info {
int dai_id;
char *dai_name;
uint8_t port;
};
struct soc_port_mapping {
// enumeration address of BT SOC
u64 ea;
struct btfmswr_dai_port_info port_info[BTFM_NUM_CODEC_DAIS];
};
struct btfmswr {
struct device *dev;
struct swr_device *swr_slave;
bool initialized;
uint32_t sample_rate;
uint32_t bps;
uint16_t direction;
uint8_t num_channels;
int soc_index;
struct soc_port_mapping *p_dai_port;
};
/**
* btfm_swr_hw_init: Initialize soundwire slave device
* Returns:
* 0: Success
* else: Fail
*/
int btfm_swr_hw_init(void);
int btfm_get_bt_soc_index(int chipset_ver);
int btfm_swr_enable_port(u8 port_num, u8 ch_count, u32 sample_rate,
u8 port_type);
int btfm_swr_disable_port(u8 port_num, u8 ch_count, u8 usecase);
/**
* btfm_swr_register_codec: Register codec driver with ALSA
* @btfmswr: swr slave device data pointer.
* Returns:
* -ENOMEM
* 0
*/
int btfm_swr_register_codec(struct btfmswr *btfmswr);
/**
* btfm_swr_unregister_codec: Unregister codec driver with ALSA
* @dev: device node
* Returns:
* VOID
*/
void btfm_swr_unregister_codec(struct device *dev);
#endif /* BTFM_SWR_H */

341
soundwire/btfm_swr_codec.c Normal file
Melihat File

@@ -0,0 +1,341 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "btfm_swr.h"
static int bt_soc_enable_status;
int btfm_feedback_ch_setting;
static int btfm_swr_codec_write(struct snd_soc_component *codec,
unsigned int reg, unsigned int value)
{
BTFMSWR_DBG("");
return 0;
}
static unsigned int btfm_swr_codec_read(struct snd_soc_component *codec,
unsigned int reg)
{
BTFMSWR_DBG("");
return 0;
}
static int btfm_soc_status_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
BTFMSWR_DBG("");
ucontrol->value.integer.value[0] = bt_soc_enable_status;
return 1;
}
static int btfm_soc_status_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
BTFMSWR_DBG("");
return 1;
}
static int btfm_get_feedback_ch_setting(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
BTFMSWR_DBG("");
ucontrol->value.integer.value[0] = btfm_feedback_ch_setting;
return 1;
}
static int btfm_put_feedback_ch_setting(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
BTFMSWR_DBG("");
btfm_feedback_ch_setting = ucontrol->value.integer.value[0];
return 1;
}
static const struct snd_kcontrol_new status_controls[] = {
SOC_SINGLE_EXT("BT SOC status", 0, 0, 1, 0,
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)
};
static int btfm_swr_codec_probe(struct snd_soc_component *codec)
{
BTFMSWR_DBG("");
snd_soc_add_component_controls(codec, status_controls,
ARRAY_SIZE(status_controls));
return 0;
}
static void btfm_swr_codec_remove(struct snd_soc_component *codec)
{
BTFMSWR_DBG("");
}
static int btfm_swr_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int ret = -1;
BTFMSWR_INFO("substream = %s stream = %d dai->name = %s",
substream->name, substream->stream, dai->name);
ret = btfm_swr_hw_init();
return ret;
}
static void btfm_swr_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int ret = 0;
u8 port_type;
BTFMSWR_INFO("dai->name: %s, dai->id: %d, dai->rate: %d", dai->name,
dai->id, dai->rate);
switch (dai->id) {
case FMAUDIO_TX:
port_type = FM_AUDIO_TX1;
break;
case BTAUDIO_TX:
port_type = BT_AUDIO_TX1;
break;
case BTAUDIO_RX:
port_type = BT_AUDIO_RX1;
break;
case BTAUDIO_A2DP_SINK_TX:
port_type = BT_AUDIO_TX2;
break;
case BTFM_NUM_CODEC_DAIS:
default:
BTFMSWR_ERR("dai->id is invalid:%d", dai->id);
return;
}
ret = btfm_swr_disable_port(pbtfmswr->p_dai_port->port_info[dai->id].port,
pbtfmswr->num_channels, port_type);
}
static int btfm_swr_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
pbtfmswr->bps = params_width(params);
pbtfmswr->direction = substream->stream;
pbtfmswr->num_channels = params_channels(params);
BTFMSWR_INFO("dai->name = %s dai id %x rate %d bps %d num_ch %d",
dai->name, dai->id, params_rate(params), params_width(params),
params_channels(params));
return 0;
}
static int btfm_swr_dai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int ret = -EINVAL;
u8 port_type;
bt_soc_enable_status = 0;
BTFMSWR_INFO("dai->name: %s, dai->id: %d, dai->rate: %d direction: %d", dai->name,
dai->id, dai->rate, pbtfmswr->direction);
/* save sample rate */
pbtfmswr->sample_rate = dai->rate;
switch (dai->id) {
case FMAUDIO_TX:
port_type = FM_AUDIO_TX1;
break;
case BTAUDIO_TX:
port_type = BT_AUDIO_TX1;
break;
case BTAUDIO_RX:
port_type = BT_AUDIO_RX1;
break;
case BTAUDIO_A2DP_SINK_TX:
port_type = BT_AUDIO_TX2;
break;
case BTFM_NUM_CODEC_DAIS:
default:
BTFMSWR_ERR("dai->id is invalid:%d", dai->id);
return -EINVAL;
}
ret = btfm_swr_enable_port(pbtfmswr->p_dai_port->port_info[dai->id].port,
pbtfmswr->num_channels, dai->rate, port_type);
/* save the enable channel status */
if (ret == 0)
bt_soc_enable_status = 1;
if (ret == -EISCONN) {
BTFMSWR_ERR("channel opened without closing, returning success");
ret = 0;
}
return ret;
}
/* This function will be called once during boot up */
static int btfm_swr_dai_set_channel_map(struct snd_soc_dai *dai,
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot)
{
BTFMSWR_DBG("");
return 0;
}
static int btfm_swr_dai_get_channel_map(struct snd_soc_dai *dai,
unsigned int *tx_num, unsigned int *tx_slot,
unsigned int *rx_num, unsigned int *rx_slot)
{
*rx_slot = 0;
*tx_slot = 0;
*rx_num = 0;
*tx_num = 0;
switch (dai->id) {
case FMAUDIO_TX:
case BTAUDIO_TX:
case BTAUDIO_A2DP_SINK_TX:
*tx_num = pbtfmswr->num_channels;
*tx_slot = pbtfmswr->num_channels == 2 ? TWO_CHANNEL_MASK :
ONE_CHANNEL_MASK;
break;
case BTAUDIO_RX:
*rx_num = pbtfmswr->num_channels;
*rx_slot = pbtfmswr->num_channels == 2 ? TWO_CHANNEL_MASK :
ONE_CHANNEL_MASK;
break;
default:
BTFMSWR_ERR("Unsupported DAI %d", dai->id);
return -EINVAL;
}
return 0;
}
static struct snd_soc_dai_ops btfmswr_dai_ops = {
.startup = btfm_swr_dai_startup,
.shutdown = btfm_swr_dai_shutdown,
.hw_params = btfm_swr_dai_hw_params,
.prepare = btfm_swr_dai_prepare,
.set_channel_map = btfm_swr_dai_set_channel_map,
.get_channel_map = btfm_swr_dai_get_channel_map,
};
static struct snd_soc_dai_driver btfmswr_dai[] = {
{ /* FM Audio data multiple channel : FM -> lpass */
.name = "btfm_fm_swr_tx",
.id = FMAUDIO_TX,
.capture = {
.stream_name = "FM TX Capture",
.rates = SNDRV_PCM_RATE_48000, /* 48 KHz */
.formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */
.rate_max = 48000,
.rate_min = 48000,
.channels_min = 1,
.channels_max = 2,
},
.ops = &btfmswr_dai_ops,
},
{ /* Bluetooth SCO voice uplink: bt -> lpass */
.name = "btfm_bt_sco_swr_tx",
.id = BTAUDIO_TX,
.capture = {
.stream_name = "SCO TX Capture",
/* 8/16/44.1/48/88.2/96/192 Khz */
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000
| SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000
| SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
.channels_max = 1,
},
.ops = &btfmswr_dai_ops,
},
{ /* Bluetooth SCO voice downlink: lpass -> bt or A2DP Playback */
.name = "btfm_bt_sco_a2dp_swr_rx",
.id = BTAUDIO_RX,
.playback = {
.stream_name = "SCO A2DP RX Playback",
/* 8/16/44.1/48/88.2/96/192 Khz */
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000
| SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000
| SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
.channels_max = 1,
},
.ops = &btfmswr_dai_ops,
},
{ /* Bluetooth A2DP sink: bt -> lpass */
.name = "btfm_a2dp_sink_swr_tx",
.id = BTAUDIO_A2DP_SINK_TX,
.capture = {
.stream_name = "A2DP sink TX Capture",
/* 8/16/44.1/48/88.2/96/192 Khz */
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000
| SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000
| SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000
| SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE, /* 16 bits */
.rate_max = 192000,
.rate_min = 8000,
.channels_min = 1,
.channels_max = 1,
},
.ops = &btfmswr_dai_ops,
},
};
static const struct snd_soc_component_driver btfmswr_codec = {
.probe = btfm_swr_codec_probe,
.remove = btfm_swr_codec_remove,
.read = btfm_swr_codec_read,
.write = btfm_swr_codec_write,
};
int btfm_swr_register_codec(struct btfmswr *btfm_swr)
{
int ret = 0;
struct device *dev = btfm_swr->dev;
BTFMSWR_DBG("");
dev_err(dev, "\n");
/* Register Codec driver */
ret = snd_soc_register_component(dev, &btfmswr_codec,
btfmswr_dai, ARRAY_SIZE(btfmswr_dai));
if (ret)
BTFMSWR_ERR("failed to register codec (%d)", ret);
return ret;
}
void btfm_swr_unregister_codec(struct device *dev)
{
BTFMSWR_DBG("");
/* Unregister Codec driver */
snd_soc_unregister_component(dev);
}
MODULE_DESCRIPTION("BTFM SoundWire Codec driver");
MODULE_LICENSE("GPL v2");

Melihat File

@@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "btfm_swr.h"
#include "btfm_swr_slave.h"
struct soc_port_mapping slave_port[] = {
// Evros
{
.ea = EVROS_EA,
.port_info[0].dai_id = FMAUDIO_TX,
.port_info[0].port = 5,
.port_info[1].dai_id = BTAUDIO_TX,
.port_info[1].port = 3,
.port_info[2].dai_id = BTAUDIO_RX,
.port_info[2].port = 1,
.port_info[3].dai_id = BTAUDIO_A2DP_SINK_TX,
.port_info[3].port = 4,
},
// Ganges
{
.ea = GANGES_EA,
// FM is not supported on Ganges. populate with invalid port number
.port_info[0].dai_id = FMAUDIO_TX,
.port_info[0].port = BTFM_INVALID_PORT,
.port_info[1].dai_id = BTAUDIO_TX,
.port_info[1].port = 4,
.port_info[2].dai_id = BTAUDIO_RX,
.port_info[2].port = 1,
.port_info[3].dai_id = BTAUDIO_A2DP_SINK_TX,
.port_info[3].port = 5,
},
};

Melihat File

@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef BTFM_SWR_SLAVE_H
#define BTFM_SWR_SLAVE_H
#include "btfm_swr.h"
/* Registers Address */
/* Register Bit Setting */
#define SLAVE_ENABLE_OVERRUN_AUTO_RECOVERY (0x1 << 1)
#define SLAVE_ENABLE_UNDERRUN_AUTO_RECOVERY (0x1 << 0)
#define SLAVE_SB_PGD_PORT_ENABLE (0x1 << 0)
#define SLAVE_SB_PGD_PORT_DISABLE (0x0 << 0)
#define BTFM_INVALID_PORT 0xFF
extern struct soc_port_mapping slave_port[];
enum {
QCA_GANGES_SOC_ID_0100 = 0x40210100,
QCA_GANGES_SOC_ID_0200 = 0x40210200,
};
enum {
QCA_EVROS_SOC_ID_0100 = 0x40200100,
QCA_EVROS_SOC_ID_0200 = 0x40200200,
};
enum {
EVROS_EA = 0x0108170220,
GANGES_EA = 0x0208170220,
};
/* Specific defines for slave slimbus device */
#define SLAVE_SWR_REG_OFFSET 0x0800
#endif