mirror of https://github.com/torvalds/linux.git
ASoC: Intel: avs: Refactor machine-board registration
Merge series from Cezary Rojewski <cezary.rojewski@intel.com>:
Set of patches all connected to the machine-board registration process
and the board_selection.c file. Apart from LOC reduction, allows for
multiple cards of the same 'type' e.g.: avs_rt5640, to be present
simultanetously without any workarounds or tricks. The last patch
improves debugability - helps us (the devs) deal with basic I2S-boards
issues out there without forcing the user to constantly switch between
debug-friendly and non-debug options.
--
Initially I wanted to have the first two patches (new implementation and
the follow up cleanup) to be just one patch. However, the git diff, even
with --patience does not look good, at least in my opinion. Decided to
split the changes into two separate patches to make it easy to review
and comment.
As the first two patches carry heaviest load, the summary:
- provide a unified avs_register_board() wrapper for
platform_device_register_data(PLATFORM_DEVID_AUTO). The _AUTO is what
makes every device name unique and prevents any naming conflicts to
occur when matching components <-> cards in runtime
- provide avs_register_board_pdata(), a wrapper one-level above
avs_register_board() that takes all custom parameters in its argument
list so that the initialization of 'struct avs_mach_pdata' does not
need to be repeated in every function like its done today
- make use of the two above to write simpler registration functions:
1. init any interface-type-specific values e.g.: SSP port for I2S
board
2. call avs_register_board_pdata()
3. register the ASoC component with avs_register_xxx_component()
In regard to the last three patches - two are simplifications, no
functional changes just LOC reduction and readability.
The last one is to improve debug-ability, especially when working in the
open field - often we, the devs, find it useful when debugging
production systems to run i2s_test (the debug board) without impacting
the 'real' board e.g.: avs_rt5640. By default i2s_test is empty so a
typical user and their scenarios are not impacted.
This commit is contained in:
commit
59f5c92140
|
|
@ -22,7 +22,6 @@
|
|||
struct avs_dev;
|
||||
struct avs_tplg;
|
||||
struct avs_tplg_library;
|
||||
struct avs_soc_component;
|
||||
struct avs_ipc_msg;
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
|
|
|||
|
|
@ -58,19 +58,13 @@ static const struct dmi_system_id kblr_dmi_table[] = {
|
|||
static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)
|
||||
{
|
||||
struct snd_soc_acpi_mach *mach = arg;
|
||||
const struct dmi_system_id *dmi_id;
|
||||
struct dmi_system_id *dmi_table;
|
||||
|
||||
if (mach->quirk_data == NULL)
|
||||
return mach;
|
||||
|
||||
dmi_table = (struct dmi_system_id *)mach->quirk_data;
|
||||
|
||||
dmi_id = dmi_first_match(dmi_table);
|
||||
if (!dmi_id)
|
||||
return NULL;
|
||||
|
||||
if (!dmi_table || dmi_first_match(dmi_table))
|
||||
return mach;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define AVS_SSP(x) (BIT(x))
|
||||
|
|
@ -388,185 +382,122 @@ static const struct avs_acpi_boards i2s_boards[] = {
|
|||
{ },
|
||||
};
|
||||
|
||||
static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)
|
||||
static struct snd_soc_acpi_mach *avs_get_i2s_machines(struct avs_dev *adev)
|
||||
{
|
||||
int id, i;
|
||||
|
||||
id = adev->base.pci->device;
|
||||
for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)
|
||||
if (i2s_boards[i].id == id)
|
||||
return &i2s_boards[i];
|
||||
return i2s_boards[i].machs;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* platform devices owned by AVS audio are removed with this hook */
|
||||
static void board_pdev_unregister(void *data)
|
||||
/* Platform devices spawned by AVS driver are removed with this hook. */
|
||||
static void avs_unregister_board(void *pdev)
|
||||
{
|
||||
platform_device_unregister(data);
|
||||
platform_device_unregister(pdev);
|
||||
}
|
||||
|
||||
static struct platform_device *avs_register_board(struct avs_dev *adev, const char *name,
|
||||
const void *data, size_t size)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_register_data(NULL, name, PLATFORM_DEVID_AUTO, data, size);
|
||||
if (IS_ERR(pdev))
|
||||
return pdev;
|
||||
|
||||
ret = devm_add_action_or_reset(adev->dev, avs_unregister_board, pdev);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return pdev;
|
||||
}
|
||||
|
||||
static struct platform_device *avs_register_board_pdata(struct avs_dev *adev, const char *name,
|
||||
struct snd_soc_acpi_mach *mach,
|
||||
struct hda_codec *codec,
|
||||
unsigned long *tdms, char *codec_name)
|
||||
{
|
||||
struct avs_mach_pdata *pdata;
|
||||
|
||||
pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pdata->codec = codec;
|
||||
pdata->tdms = tdms;
|
||||
pdata->codec_name = codec_name;
|
||||
pdata->obsolete_card_names = obsolete_card_names;
|
||||
mach->pdata = pdata;
|
||||
|
||||
return avs_register_board(adev, name, mach, sizeof(*mach));
|
||||
}
|
||||
|
||||
static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)
|
||||
{
|
||||
struct platform_device *board;
|
||||
struct snd_soc_acpi_mach mach = {{0}};
|
||||
int ret;
|
||||
struct platform_device *pdev;
|
||||
|
||||
ret = avs_register_probe_component(adev, "probe-platform");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pdev = avs_register_board(adev, "avs_probe_mb", NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
mach.mach_params.platform = "probe-platform";
|
||||
|
||||
board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE,
|
||||
(const void *)&mach, sizeof(mach));
|
||||
if (IS_ERR(board)) {
|
||||
dev_err(adev->dev, "probe board register failed\n");
|
||||
return PTR_ERR(board);
|
||||
}
|
||||
|
||||
ret = devm_add_action(adev->dev, board_pdev_unregister, board);
|
||||
if (ret < 0) {
|
||||
platform_device_unregister(board);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
return avs_register_probe_component(adev, dev_name(&pdev->dev));
|
||||
}
|
||||
|
||||
static int avs_register_dmic_board(struct avs_dev *adev)
|
||||
{
|
||||
struct platform_device *codec, *board;
|
||||
struct snd_soc_acpi_mach mach = {{0}};
|
||||
struct avs_mach_pdata *pdata;
|
||||
int ret;
|
||||
static struct snd_soc_acpi_mach mach = {
|
||||
.tplg_filename = "dmic-tplg.bin",
|
||||
};
|
||||
struct platform_device *pdev;
|
||||
char *codec_name;
|
||||
|
||||
if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) {
|
||||
dev_dbg(adev->dev, "no DMIC endpoints present\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
|
||||
if (IS_ERR(codec)) {
|
||||
dev_err(adev->dev, "dmic codec register failed\n");
|
||||
return PTR_ERR(codec);
|
||||
}
|
||||
/* DMIC present in Intel PCH is enumerated statically. */
|
||||
pdev = avs_register_board(adev, "dmic-codec", NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
ret = devm_add_action(adev->dev, board_pdev_unregister, codec);
|
||||
if (ret < 0) {
|
||||
platform_device_unregister(codec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = avs_register_dmic_component(adev, "dmic-platform");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
pdata->obsolete_card_names = obsolete_card_names;
|
||||
mach.pdata = pdata;
|
||||
mach.tplg_filename = "dmic-tplg.bin";
|
||||
mach.mach_params.platform = "dmic-platform";
|
||||
|
||||
board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE,
|
||||
(const void *)&mach, sizeof(mach));
|
||||
if (IS_ERR(board)) {
|
||||
dev_err(adev->dev, "dmic board register failed\n");
|
||||
return PTR_ERR(board);
|
||||
}
|
||||
|
||||
ret = devm_add_action(adev->dev, board_pdev_unregister, board);
|
||||
if (ret < 0) {
|
||||
platform_device_unregister(board);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
|
||||
{
|
||||
struct platform_device *board;
|
||||
struct avs_mach_pdata *pdata;
|
||||
int num_ssps;
|
||||
char *name;
|
||||
int ret;
|
||||
int uid;
|
||||
|
||||
num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
|
||||
if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
|
||||
dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
|
||||
num_ssps, mach->drv_name,
|
||||
(unsigned long)__fls(mach->mach_params.i2s_link_mask));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdata = mach->pdata;
|
||||
if (!pdata)
|
||||
pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
pdata->obsolete_card_names = obsolete_card_names;
|
||||
mach->pdata = pdata;
|
||||
|
||||
uid = mach->mach_params.i2s_link_mask;
|
||||
if (avs_mach_singular_ssp(mach))
|
||||
uid = (uid << AVS_CHANNELS_MAX) + avs_mach_ssp_tdm(mach, avs_mach_ssp_port(mach));
|
||||
|
||||
name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name, uid);
|
||||
if (!name)
|
||||
codec_name = devm_kstrdup(adev->dev, dev_name(&pdev->dev), GFP_KERNEL);
|
||||
if (!codec_name)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = avs_register_i2s_component(adev, name, mach->mach_params.i2s_link_mask, pdata->tdms);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pdev = avs_register_board_pdata(adev, "avs_dmic", &mach, NULL, NULL, codec_name);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
mach->mach_params.platform = name;
|
||||
|
||||
board = platform_device_register_data(NULL, mach->drv_name, uid,
|
||||
(const void *)mach, sizeof(*mach));
|
||||
if (IS_ERR(board)) {
|
||||
dev_err(adev->dev, "ssp board register failed\n");
|
||||
return PTR_ERR(board);
|
||||
}
|
||||
|
||||
ret = devm_add_action(adev->dev, board_pdev_unregister, board);
|
||||
if (ret < 0) {
|
||||
platform_device_unregister(board);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return avs_register_dmic_component(adev, dev_name(&pdev->dev));
|
||||
}
|
||||
|
||||
static int avs_register_i2s_test_board(struct avs_dev *adev, int ssp_port, int tdm_slot)
|
||||
{
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
int tdm_mask = BIT(tdm_slot);
|
||||
unsigned long *tdm_cfg;
|
||||
char *tplg_name;
|
||||
int ret;
|
||||
struct snd_soc_acpi_mach mach = {{0}};
|
||||
struct platform_device *pdev;
|
||||
unsigned long *tdms;
|
||||
|
||||
mach = devm_kzalloc(adev->dev, sizeof(*mach), GFP_KERNEL);
|
||||
tdm_cfg = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(unsigned long), GFP_KERNEL);
|
||||
tplg_name = devm_kasprintf(adev->dev, GFP_KERNEL, AVS_STRING_FMT("i2s", "-test-tplg.bin",
|
||||
tdms = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(*tdms), GFP_KERNEL);
|
||||
mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,
|
||||
AVS_STRING_FMT("i2s", "-test-tplg.bin",
|
||||
ssp_port, tdm_slot));
|
||||
if (!mach || !tdm_cfg || !tplg_name)
|
||||
if (!tdms || !mach.tplg_filename)
|
||||
return -ENOMEM;
|
||||
|
||||
mach->drv_name = "avs_i2s_test";
|
||||
mach->mach_params.i2s_link_mask = AVS_SSP(ssp_port);
|
||||
tdm_cfg[ssp_port] = tdm_mask;
|
||||
mach->pdata = tdm_cfg;
|
||||
mach->tplg_filename = tplg_name;
|
||||
tdms[ssp_port] = BIT(tdm_slot);
|
||||
mach.drv_name = "avs_i2s_test";
|
||||
mach.mach_params.i2s_link_mask = AVS_SSP(ssp_port);
|
||||
|
||||
ret = avs_register_i2s_board(adev, mach);
|
||||
if (ret < 0) {
|
||||
dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);
|
||||
return ret;
|
||||
}
|
||||
pdev = avs_register_board_pdata(adev, mach.drv_name, &mach, NULL, tdms, NULL);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
return 0;
|
||||
return avs_register_i2s_component(adev, dev_name(&pdev->dev), AVS_SSP(ssp_port), tdms);
|
||||
}
|
||||
|
||||
static int avs_register_i2s_test_boards(struct avs_dev *adev)
|
||||
|
|
@ -576,6 +507,9 @@ static int avs_register_i2s_test_boards(struct avs_dev *adev)
|
|||
unsigned long tdm_slots;
|
||||
u32 *array, num_elems;
|
||||
|
||||
if (!i2s_test)
|
||||
return 0;
|
||||
|
||||
ret = parse_int_array(i2s_test, strlen(i2s_test), (int **)&array);
|
||||
if (ret) {
|
||||
dev_err(adev->dev, "failed to parse i2s_test parameter\n");
|
||||
|
|
@ -601,9 +535,26 @@ static int avs_register_i2s_test_boards(struct avs_dev *adev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
|
||||
{
|
||||
u32 i2s_mask = mach->mach_params.i2s_link_mask;
|
||||
struct platform_device *pdev;
|
||||
unsigned long *tdms = NULL;
|
||||
|
||||
if (mach->pdata)
|
||||
tdms = ((struct avs_mach_pdata *)mach->pdata)->tdms;
|
||||
|
||||
pdev = avs_register_board_pdata(adev, mach->drv_name, mach, NULL, tdms, NULL);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
return avs_register_i2s_component(adev, dev_name(&pdev->dev), i2s_mask, tdms);
|
||||
}
|
||||
|
||||
static int avs_register_i2s_boards(struct avs_dev *adev)
|
||||
{
|
||||
const struct avs_acpi_boards *boards;
|
||||
int num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
|
||||
struct snd_soc_acpi_mach *machs;
|
||||
struct snd_soc_acpi_mach *mach;
|
||||
int ret;
|
||||
|
||||
|
|
@ -612,19 +563,22 @@ static int avs_register_i2s_boards(struct avs_dev *adev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (i2s_test)
|
||||
return avs_register_i2s_test_boards(adev);
|
||||
|
||||
boards = avs_get_i2s_boards(adev);
|
||||
if (!boards) {
|
||||
machs = avs_get_i2s_machines(adev);
|
||||
if (!machs) {
|
||||
dev_dbg(adev->dev, "no I2S endpoints supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (mach = boards->machs; mach->id[0]; mach++) {
|
||||
for (mach = machs; mach->id[0]; mach++) {
|
||||
if (!acpi_dev_present(mach->id, mach->uid, -1))
|
||||
continue;
|
||||
|
||||
if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
|
||||
dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
|
||||
num_ssps, mach->drv_name,
|
||||
(unsigned long)__fls(mach->mach_params.i2s_link_mask));
|
||||
continue;
|
||||
}
|
||||
if (mach->machine_quirk)
|
||||
if (!mach->machine_quirk(mach))
|
||||
continue;
|
||||
|
|
@ -639,49 +593,20 @@ static int avs_register_i2s_boards(struct avs_dev *adev)
|
|||
|
||||
static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
|
||||
{
|
||||
struct snd_soc_acpi_mach mach = {{0}};
|
||||
struct platform_device *board;
|
||||
struct avs_mach_pdata *pdata;
|
||||
struct hdac_device *hdev = &codec->core;
|
||||
char *pname;
|
||||
int ret, id;
|
||||
struct snd_soc_acpi_mach mach = {{0}};
|
||||
struct platform_device *pdev;
|
||||
|
||||
pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));
|
||||
if (!pname)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
pdata->obsolete_card_names = obsolete_card_names;
|
||||
pdata->codec = codec;
|
||||
|
||||
ret = avs_register_hda_component(adev, pname);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mach.pdata = pdata;
|
||||
mach.mach_params.platform = pname;
|
||||
mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
|
||||
hdev->vendor_id);
|
||||
if (!mach.tplg_filename)
|
||||
return -ENOMEM;
|
||||
|
||||
id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;
|
||||
board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,
|
||||
sizeof(mach));
|
||||
if (IS_ERR(board)) {
|
||||
dev_err(adev->dev, "hda board register failed\n");
|
||||
return PTR_ERR(board);
|
||||
}
|
||||
pdev = avs_register_board_pdata(adev, "avs_hdaudio", &mach, codec, NULL, NULL);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
ret = devm_add_action(adev->dev, board_pdev_unregister, board);
|
||||
if (ret < 0) {
|
||||
platform_device_unregister(board);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return avs_register_hda_component(adev, dev_name(&pdev->dev));
|
||||
}
|
||||
|
||||
static int avs_register_hda_boards(struct avs_dev *adev)
|
||||
|
|
@ -724,6 +649,10 @@ int avs_register_all_boards(struct avs_dev *adev)
|
|||
dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
|
||||
ret);
|
||||
|
||||
ret = avs_register_i2s_test_boards(adev);
|
||||
if (ret)
|
||||
dev_dbg(adev->dev, "enumerate I2S TEST endpoints failed: %d\n", ret);
|
||||
|
||||
ret = avs_register_i2s_boards(adev);
|
||||
if (ret < 0)
|
||||
dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
|
||||
|
|
|
|||
Loading…
Reference in New Issue