162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for Digigram VX soundcards
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * DSP firmware management
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/device.h>
1162306a36Sopenharmony_ci#include <linux/firmware.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/vmalloc.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <sound/core.h>
1662306a36Sopenharmony_ci#include <sound/hwdep.h>
1762306a36Sopenharmony_ci#include <sound/vx_core.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciMODULE_FIRMWARE("vx/bx_1_vxp.b56");
2062306a36Sopenharmony_ciMODULE_FIRMWARE("vx/bx_1_vp4.b56");
2162306a36Sopenharmony_ciMODULE_FIRMWARE("vx/x1_1_vx2.xlx");
2262306a36Sopenharmony_ciMODULE_FIRMWARE("vx/x1_2_v22.xlx");
2362306a36Sopenharmony_ciMODULE_FIRMWARE("vx/x1_1_vxp.xlx");
2462306a36Sopenharmony_ciMODULE_FIRMWARE("vx/x1_1_vp4.xlx");
2562306a36Sopenharmony_ciMODULE_FIRMWARE("vx/bd56002.boot");
2662306a36Sopenharmony_ciMODULE_FIRMWARE("vx/bd563v2.boot");
2762306a36Sopenharmony_ciMODULE_FIRMWARE("vx/bd563s3.boot");
2862306a36Sopenharmony_ciMODULE_FIRMWARE("vx/l_1_vx2.d56");
2962306a36Sopenharmony_ciMODULE_FIRMWARE("vx/l_1_v22.d56");
3062306a36Sopenharmony_ciMODULE_FIRMWARE("vx/l_1_vxp.d56");
3162306a36Sopenharmony_ciMODULE_FIRMWARE("vx/l_1_vp4.d56");
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciint snd_vx_setup_firmware(struct vx_core *chip)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	static const char * const fw_files[VX_TYPE_NUMS][4] = {
3662306a36Sopenharmony_ci		[VX_TYPE_BOARD] = {
3762306a36Sopenharmony_ci			NULL, "x1_1_vx2.xlx", "bd56002.boot", "l_1_vx2.d56",
3862306a36Sopenharmony_ci		},
3962306a36Sopenharmony_ci		[VX_TYPE_V2] = {
4062306a36Sopenharmony_ci			NULL, "x1_2_v22.xlx", "bd563v2.boot", "l_1_v22.d56",
4162306a36Sopenharmony_ci		},
4262306a36Sopenharmony_ci		[VX_TYPE_MIC] = {
4362306a36Sopenharmony_ci			NULL, "x1_2_v22.xlx", "bd563v2.boot", "l_1_v22.d56",
4462306a36Sopenharmony_ci		},
4562306a36Sopenharmony_ci		[VX_TYPE_VXPOCKET] = {
4662306a36Sopenharmony_ci			"bx_1_vxp.b56", "x1_1_vxp.xlx", "bd563s3.boot", "l_1_vxp.d56"
4762306a36Sopenharmony_ci		},
4862306a36Sopenharmony_ci		[VX_TYPE_VXP440] = {
4962306a36Sopenharmony_ci			"bx_1_vp4.b56", "x1_1_vp4.xlx", "bd563s3.boot", "l_1_vp4.d56"
5062306a36Sopenharmony_ci		},
5162306a36Sopenharmony_ci	};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	int i, err;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
5662306a36Sopenharmony_ci		char path[32];
5762306a36Sopenharmony_ci		const struct firmware *fw;
5862306a36Sopenharmony_ci		if (! fw_files[chip->type][i])
5962306a36Sopenharmony_ci			continue;
6062306a36Sopenharmony_ci		sprintf(path, "vx/%s", fw_files[chip->type][i]);
6162306a36Sopenharmony_ci		if (request_firmware(&fw, path, chip->dev)) {
6262306a36Sopenharmony_ci			snd_printk(KERN_ERR "vx: can't load firmware %s\n", path);
6362306a36Sopenharmony_ci			return -ENOENT;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci		err = chip->ops->load_dsp(chip, i, fw);
6662306a36Sopenharmony_ci		if (err < 0) {
6762306a36Sopenharmony_ci			release_firmware(fw);
6862306a36Sopenharmony_ci			return err;
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci		if (i == 1)
7162306a36Sopenharmony_ci			chip->chip_status |= VX_STAT_XILINX_LOADED;
7262306a36Sopenharmony_ci#ifdef CONFIG_PM
7362306a36Sopenharmony_ci		chip->firmware[i] = fw;
7462306a36Sopenharmony_ci#else
7562306a36Sopenharmony_ci		release_firmware(fw);
7662306a36Sopenharmony_ci#endif
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* ok, we reached to the last one */
8062306a36Sopenharmony_ci	/* create the devices if not built yet */
8162306a36Sopenharmony_ci	err = snd_vx_pcm_new(chip);
8262306a36Sopenharmony_ci	if (err < 0)
8362306a36Sopenharmony_ci		return err;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	err = snd_vx_mixer_new(chip);
8662306a36Sopenharmony_ci	if (err < 0)
8762306a36Sopenharmony_ci		return err;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (chip->ops->add_controls) {
9062306a36Sopenharmony_ci		err = chip->ops->add_controls(chip);
9162306a36Sopenharmony_ci		if (err < 0)
9262306a36Sopenharmony_ci			return err;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	chip->chip_status |= VX_STAT_DEVICE_INIT;
9662306a36Sopenharmony_ci	chip->chip_status |= VX_STAT_CHIP_INIT;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return snd_card_register(chip->card);
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* exported */
10262306a36Sopenharmony_civoid snd_vx_free_firmware(struct vx_core *chip)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci#ifdef CONFIG_PM
10562306a36Sopenharmony_ci	int i;
10662306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
10762306a36Sopenharmony_ci		release_firmware(chip->firmware[i]);
10862306a36Sopenharmony_ci#endif
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ciEXPORT_SYMBOL(snd_vx_setup_firmware);
11262306a36Sopenharmony_ciEXPORT_SYMBOL(snd_vx_free_firmware);
113