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