Merge branch 'topic/cs35l41' into for-next

Pull CS35L41 codec extension series.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2023-12-29 15:14:02 +01:00
commit 3abf66a42f
53 changed files with 1057 additions and 332 deletions

View File

@ -253,6 +253,7 @@ static const char * const snd_pcm_state_names[] = {
STATE(DRAINING),
STATE(PAUSED),
STATE(SUSPENDED),
STATE(DISCONNECTED),
};
static const char * const snd_pcm_access_names[] = {

View File

@ -397,7 +397,6 @@ static int snd_pcmtst_pcm_close(struct snd_pcm_substream *substream)
struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
timer_shutdown_sync(&v_iter->timer_instance);
v_iter->substream = NULL;
playback_capture_test = !v_iter->is_buf_corrupted;
kfree(v_iter);
return 0;
@ -435,6 +434,7 @@ static int snd_pcmtst_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
// We can't call timer_shutdown_sync here, as it is forbidden to sleep here
v_iter->suspend = true;
timer_delete(&v_iter->timer_instance);
break;
}
@ -512,12 +512,22 @@ static int snd_pcmtst_ioctl(struct snd_pcm_substream *substream, unsigned int cm
return snd_pcm_lib_ioctl(substream, cmd, arg);
}
static int snd_pcmtst_sync_stop(struct snd_pcm_substream *substream)
{
struct pcmtst_buf_iter *v_iter = substream->runtime->private_data;
timer_delete_sync(&v_iter->timer_instance);
return 0;
}
static const struct snd_pcm_ops snd_pcmtst_playback_ops = {
.open = snd_pcmtst_pcm_open,
.close = snd_pcmtst_pcm_close,
.trigger = snd_pcmtst_pcm_trigger,
.hw_params = snd_pcmtst_pcm_hw_params,
.ioctl = snd_pcmtst_ioctl,
.sync_stop = snd_pcmtst_sync_stop,
.hw_free = snd_pcmtst_pcm_hw_free,
.prepare = snd_pcmtst_pcm_prepare,
.pointer = snd_pcmtst_pcm_pointer,
@ -530,6 +540,7 @@ static const struct snd_pcm_ops snd_pcmtst_capture_ops = {
.hw_params = snd_pcmtst_pcm_hw_params,
.hw_free = snd_pcmtst_pcm_hw_free,
.ioctl = snd_pcmtst_ioctl,
.sync_stop = snd_pcmtst_sync_stop,
.prepare = snd_pcmtst_pcm_prepare,
.pointer = snd_pcmtst_pcm_pointer,
};

View File

@ -238,7 +238,7 @@ EXPORT_SYMBOL(intel_nhlt_ssp_mclk_mask);
static struct nhlt_specific_cfg *
nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch,
u32 rate, u8 vbps, u8 bps)
u32 rate, u8 vbps, u8 bps, bool ignore_vbps)
{
struct nhlt_fmt_cfg *cfg = fmt->fmt_config;
struct wav_fmt *wfmt;
@ -255,8 +255,12 @@ nhlt_get_specific_cfg(struct device *dev, struct nhlt_fmt *fmt, u8 num_ch,
dev_dbg(dev, "Endpoint format: ch=%d fmt=%d/%d rate=%d\n",
wfmt->channels, _vbps, _bps, wfmt->samples_per_sec);
/*
* When looking for exact match of configuration ignore the vbps
* from NHLT table when ignore_vbps is true
*/
if (wfmt->channels == num_ch && wfmt->samples_per_sec == rate &&
vbps == _vbps && bps == _bps)
(ignore_vbps || vbps == _vbps) && bps == _bps)
return &cfg->config;
cfg = (struct nhlt_fmt_cfg *)(cfg->config.caps + cfg->config.size);
@ -289,6 +293,7 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
{
struct nhlt_specific_cfg *cfg;
struct nhlt_endpoint *epnt;
bool ignore_vbps = false;
struct nhlt_fmt *fmt;
int i;
@ -298,7 +303,26 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
dev_dbg(dev, "Looking for configuration:\n");
dev_dbg(dev, " vbus_id=%d link_type=%d dir=%d, dev_type=%d\n",
bus_id, link_type, dir, dev_type);
dev_dbg(dev, " ch=%d fmt=%d/%d rate=%d\n", num_ch, vbps, bps, rate);
if (link_type == NHLT_LINK_DMIC && bps == 32 && (vbps == 24 || vbps == 32)) {
/*
* The DMIC hardware supports only one type of 32 bits sample
* size, which is 24 bit sampling on the MSB side and bits[1:0]
* are used for indicating the channel number.
* It has been observed that some NHLT tables have the vbps
* specified as 32 while some uses 24.
* The format these variations describe are identical, the
* hardware is configured and behaves the same way.
* Note: when the samples assumed to be vbps=32 then the 'noise'
* introduced by the lower two bits (channel number) have no
* real life implication on audio quality.
*/
dev_dbg(dev,
" ch=%d fmt=%d rate=%d (vbps is ignored for DMIC 32bit format)\n",
num_ch, bps, rate);
ignore_vbps = true;
} else {
dev_dbg(dev, " ch=%d fmt=%d/%d rate=%d\n", num_ch, vbps, bps, rate);
}
dev_dbg(dev, "Endpoint count=%d\n", nhlt->endpoint_count);
epnt = (struct nhlt_endpoint *)nhlt->desc;
@ -307,7 +331,8 @@ intel_nhlt_get_endpoint_blob(struct device *dev, struct nhlt_acpi_table *nhlt,
if (nhlt_check_ep_match(dev, epnt, bus_id, link_type, dir, dev_type)) {
fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size);
cfg = nhlt_get_specific_cfg(dev, fmt, num_ch, rate, vbps, bps);
cfg = nhlt_get_specific_cfg(dev, fmt, num_ch, rate,
vbps, bps, ignore_vbps);
if (cfg)
return cfg;
}

View File

@ -12,6 +12,7 @@
#include <sound/hda_codec.h>
#include <sound/soc.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
#include "hda_local.h"
#include "hda_auto_parser.h"
#include "hda_jack.h"
@ -996,6 +997,11 @@ static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
__be32 halo_sts;
int ret;
if (cs35l41->bypass_fw) {
dev_warn(cs35l41->dev, "Bypassing Firmware.\n");
return 0;
}
ret = cs35l41_init_dsp(cs35l41);
if (ret) {
dev_warn(cs35l41->dev, "Cannot Initialize Firmware. Error: %d\n", ret);
@ -1588,6 +1594,7 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
u32 values[HDA_MAX_COMPONENTS];
struct acpi_device *adev;
struct device *physdev;
struct spi_device *spi;
const char *sub;
char *property;
size_t nval;
@ -1610,7 +1617,7 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid);
if (!ret) {
dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n");
goto put_physdev;
goto out;
}
property = "cirrus,dev-index";
@ -1701,8 +1708,20 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
hw_cfg->bst_type = CS35L41_EXT_BOOST;
hw_cfg->valid = true;
out:
put_device(physdev);
cs35l41->bypass_fw = false;
if (cs35l41->control_bus == SPI) {
spi = to_spi_device(cs35l41->dev);
if (spi->max_speed_hz < CS35L41_MAX_ACCEPTABLE_SPI_SPEED_HZ) {
dev_warn(cs35l41->dev,
"SPI speed is too slow to support firmware download: %d Hz.\n",
spi->max_speed_hz);
cs35l41->bypass_fw = true;
}
}
return 0;
err:
@ -1711,14 +1730,13 @@ err:
hw_cfg->gpio1.valid = false;
hw_cfg->gpio2.valid = false;
acpi_dev_put(cs35l41->dacpi);
put_physdev:
put_device(physdev);
return ret;
}
int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
struct regmap *regmap)
struct regmap *regmap, enum control_bus control_bus)
{
unsigned int regid, reg_revid;
struct cs35l41_hda *cs35l41;
@ -1737,6 +1755,7 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
cs35l41->dev = dev;
cs35l41->irq = irq;
cs35l41->regmap = regmap;
cs35l41->control_bus = control_bus;
dev_set_drvdata(dev, cs35l41);
ret = cs35l41_hda_read_acpi(cs35l41, device_name, id);
@ -1826,6 +1845,7 @@ err:
if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
gpiod_put(cs35l41->cs_gpio);
acpi_dev_put(cs35l41->dacpi);
kfree(cs35l41->acpi_subsystem_id);
@ -1853,6 +1873,7 @@ void cs35l41_hda_remove(struct device *dev)
if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
gpiod_put(cs35l41->reset_gpio);
gpiod_put(cs35l41->cs_gpio);
kfree(cs35l41->acpi_subsystem_id);
}
EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, SND_HDA_SCODEC_CS35L41);

View File

@ -20,6 +20,8 @@
#include <linux/firmware/cirrus/cs_dsp.h>
#include <linux/firmware/cirrus/wmfw.h>
#define CS35L41_MAX_ACCEPTABLE_SPI_SPEED_HZ 1000000
struct cs35l41_amp_cal_data {
u32 calTarget[2];
u32 calTime[2];
@ -35,8 +37,8 @@ struct cs35l41_amp_efi_data {
} __packed;
enum cs35l41_hda_spk_pos {
CS35l41_LEFT,
CS35l41_RIGHT,
CS35L41_LEFT,
CS35L41_RIGHT,
};
enum cs35l41_hda_gpio_function {
@ -46,10 +48,16 @@ enum cs35l41_hda_gpio_function {
CS35l41_SYNC,
};
enum control_bus {
I2C,
SPI
};
struct cs35l41_hda {
struct device *dev;
struct regmap *regmap;
struct gpio_desc *reset_gpio;
struct gpio_desc *cs_gpio;
struct cs35l41_hw_cfg hw_cfg;
struct hda_codec *codec;
@ -73,6 +81,9 @@ struct cs35l41_hda {
struct cs_dsp cs_dsp;
struct acpi_device *dacpi;
bool mute_override;
enum control_bus control_bus;
bool bypass_fw;
};
enum halo_state {
@ -84,7 +95,7 @@ enum halo_state {
extern const struct dev_pm_ops cs35l41_hda_pm_ops;
int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
struct regmap *regmap);
struct regmap *regmap, enum control_bus control_bus);
void cs35l41_hda_remove(struct device *dev);
int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id);

View File

@ -30,7 +30,7 @@ static int cs35l41_hda_i2c_probe(struct i2c_client *clt)
return -ENODEV;
return cs35l41_hda_probe(&clt->dev, device_name, clt->addr, clt->irq,
devm_regmap_init_i2c(clt, &cs35l41_regmap_i2c));
devm_regmap_init_i2c(clt, &cs35l41_regmap_i2c), I2C);
}
static void cs35l41_hda_i2c_remove(struct i2c_client *clt)

View File

@ -6,9 +6,303 @@
//
// Author: Stefan Binding <sbinding@opensource.cirrus.com>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/string.h>
#include "cs35l41_hda_property.h"
#include <linux/spi/spi.h>
#define MAX_AMPS 4
struct cs35l41_config {
const char *ssid;
int num_amps;
enum {
INTERNAL,
EXTERNAL
} boost_type;
u8 channel[MAX_AMPS];
int reset_gpio_index; /* -1 if no reset gpio */
int spkid_gpio_index; /* -1 if no spkid gpio */
int cs_gpio_index; /* -1 if no cs gpio, or cs-gpios already exists, max num amps == 2 */
int boost_ind_nanohenry; /* Required if boost_type == Internal */
int boost_peak_milliamp; /* Required if boost_type == Internal */
int boost_cap_microfarad; /* Required if boost_type == Internal */
};
static const struct cs35l41_config cs35l41_config_table[] = {
{ "10280B27", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10280B28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10280BEB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
{ "10280C4D", 4, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT }, 0, 1, -1, 1000, 4500, 24 },
/*
* Device 103C89C6 does have _DSD, however it is setup to use the wrong boost type.
* We can override the _DSD to correct the boost type here.
* Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists
* in the ACPI. The Reset GPIO is also valid, so we can use the Reset defined in _DSD.
*/
{ "103C89C6", 2, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, -1, -1, -1, 1000, 4500, 24 },
{ "104312AF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10431433", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431463", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431473", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
{ "10431483", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
{ "10431493", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "104314D3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "104314E3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431503", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431533", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431573", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10431663", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
{ "104316D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
{ "104316F3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
{ "104317F3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431863", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "104318D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
{ "10431C9F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10431CAF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10431CCF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10431CDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10431CEF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10431D1F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431DA2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
{ "10431E02", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
{ "10431EE2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "10431F12", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
{ "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
{}
};
static int cs35l41_add_gpios(struct cs35l41_hda *cs35l41, struct device *physdev, int reset_gpio,
int spkid_gpio, int cs_gpio_index, int num_amps)
{
struct acpi_gpio_mapping *gpio_mapping = NULL;
struct acpi_gpio_params *reset_gpio_params = NULL;
struct acpi_gpio_params *spkid_gpio_params = NULL;
struct acpi_gpio_params *cs_gpio_params = NULL;
unsigned int num_entries = 0;
unsigned int reset_index, spkid_index, csgpio_index;
int i;
/*
* GPIO Mapping only needs to be done once, since it would be available for subsequent amps
*/
if (cs35l41->dacpi->driver_gpios)
return 0;
if (reset_gpio >= 0) {
reset_index = num_entries;
num_entries++;
}
if (spkid_gpio >= 0) {
spkid_index = num_entries;
num_entries++;
}
if ((cs_gpio_index >= 0) && (num_amps == 2)) {
csgpio_index = num_entries;
num_entries++;
}
if (!num_entries)
return 0;
/* must include termination entry */
num_entries++;
gpio_mapping = devm_kcalloc(physdev, num_entries, sizeof(struct acpi_gpio_mapping),
GFP_KERNEL);
if (!gpio_mapping)
goto err;
if (reset_gpio >= 0) {
gpio_mapping[reset_index].name = "reset-gpios";
reset_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),
GFP_KERNEL);
if (!reset_gpio_params)
goto err;
for (i = 0; i < num_amps; i++)
reset_gpio_params[i].crs_entry_index = reset_gpio;
gpio_mapping[reset_index].data = reset_gpio_params;
gpio_mapping[reset_index].size = num_amps;
}
if (spkid_gpio >= 0) {
gpio_mapping[spkid_index].name = "spk-id-gpios";
spkid_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),
GFP_KERNEL);
if (!spkid_gpio_params)
goto err;
for (i = 0; i < num_amps; i++)
spkid_gpio_params[i].crs_entry_index = spkid_gpio;
gpio_mapping[spkid_index].data = spkid_gpio_params;
gpio_mapping[spkid_index].size = num_amps;
}
if ((cs_gpio_index >= 0) && (num_amps == 2)) {
gpio_mapping[csgpio_index].name = "cs-gpios";
/* only one GPIO CS is supported without using _DSD, obtained using index 0 */
cs_gpio_params = devm_kzalloc(physdev, sizeof(struct acpi_gpio_params), GFP_KERNEL);
if (!cs_gpio_params)
goto err;
cs_gpio_params->crs_entry_index = cs_gpio_index;
gpio_mapping[csgpio_index].data = cs_gpio_params;
gpio_mapping[csgpio_index].size = 1;
}
return devm_acpi_dev_add_driver_gpios(physdev, gpio_mapping);
err:
devm_kfree(physdev, gpio_mapping);
devm_kfree(physdev, reset_gpio_params);
devm_kfree(physdev, spkid_gpio_params);
devm_kfree(physdev, cs_gpio_params);
return -ENOMEM;
}
static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
const char *hid)
{
struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
const struct cs35l41_config *cfg;
struct gpio_desc *cs_gpiod;
struct spi_device *spi;
bool dsd_found;
int ret;
for (cfg = cs35l41_config_table; cfg->ssid; cfg++) {
if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id))
break;
}
if (!cfg->ssid)
return -ENOENT;
if (!cs35l41->dacpi || cs35l41->dacpi != ACPI_COMPANION(physdev)) {
dev_err(cs35l41->dev, "ACPI Device does not match, cannot override _DSD.\n");
return -ENODEV;
}
dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);
dsd_found = acpi_dev_has_props(cs35l41->dacpi);
if (!dsd_found) {
ret = cs35l41_add_gpios(cs35l41, physdev, cfg->reset_gpio_index,
cfg->spkid_gpio_index, cfg->cs_gpio_index,
cfg->num_amps);
if (ret) {
dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);
return ret;
}
} else if (cfg->reset_gpio_index >= 0 || cfg->spkid_gpio_index >= 0) {
dev_warn(cs35l41->dev, "Cannot add Reset/Speaker ID/SPI CS GPIO Mapping, "
"_DSD already exists.\n");
}
if (cs35l41->control_bus == SPI) {
cs35l41->index = id;
#if IS_ENABLED(CONFIG_SPI)
/*
* Manually set the Chip Select for the second amp <cs_gpio_index> in the node.
* This is only supported for systems with 2 amps, since we cannot expand the
* default number of chip selects without using cs-gpios
* The CS GPIO must be set high prior to communicating with the first amp (which
* uses a native chip select), to ensure the second amp does not clash with the
* first.
*/
if (cfg->cs_gpio_index >= 0) {
spi = to_spi_device(cs35l41->dev);
if (cfg->num_amps != 2) {
dev_warn(cs35l41->dev,
"Cannot update SPI CS, Number of Amps (%d) != 2\n",
cfg->num_amps);
} else if (dsd_found) {
dev_warn(cs35l41->dev,
"Cannot update SPI CS, _DSD already exists.\n");
} else {
/*
* This is obtained using driver_gpios, since only one GPIO for CS
* exists, this can be obtained using index 0.
*/
cs_gpiod = gpiod_get_index(physdev, "cs", 0, GPIOD_OUT_LOW);
if (IS_ERR(cs_gpiod)) {
dev_err(cs35l41->dev,
"Unable to get Chip Select GPIO descriptor\n");
return PTR_ERR(cs_gpiod);
}
if (id == 1) {
spi_set_csgpiod(spi, 0, cs_gpiod);
cs35l41->cs_gpio = cs_gpiod;
} else {
gpiod_set_value_cansleep(cs_gpiod, true);
gpiod_put(cs_gpiod);
}
spi_setup(spi);
}
}
#endif
} else {
if (cfg->num_amps > 2)
/*
* i2c addresses for 3/4 amps are used in order: 0x40, 0x41, 0x42, 0x43,
* subtracting 0x40 would give zero-based index
*/
cs35l41->index = id - 0x40;
else
/* i2c addr 0x40 for first amp (always), 0x41/0x42 for 2nd amp */
cs35l41->index = id == 0x40 ? 0 : 1;
}
if (cfg->num_amps == 3)
/* 3 amps means a center channel, so no duplicate channels */
cs35l41->channel_index = 0;
else
/*
* if 4 amps, there are duplicate channels, so they need different indexes
* if 2 amps, no duplicate channels, channel_index would be 0
*/
cs35l41->channel_index = cs35l41->index / 2;
cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
cs35l41->index, GPIOD_OUT_LOW,
"cs35l41-reset");
cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, cfg->num_amps, -1);
hw_cfg->spk_pos = cfg->channel[cs35l41->index];
if (cfg->boost_type == INTERNAL) {
hw_cfg->bst_type = CS35L41_INT_BOOST;
hw_cfg->bst_ind = cfg->boost_ind_nanohenry;
hw_cfg->bst_ipk = cfg->boost_peak_milliamp;
hw_cfg->bst_cap = cfg->boost_cap_microfarad;
hw_cfg->gpio1.func = CS35L41_NOT_USED;
hw_cfg->gpio1.valid = true;
} else {
hw_cfg->bst_type = CS35L41_EXT_BOOST;
hw_cfg->bst_ind = -1;
hw_cfg->bst_ipk = -1;
hw_cfg->bst_cap = -1;
hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
hw_cfg->gpio1.valid = true;
}
hw_cfg->gpio2.func = CS35L41_INTERRUPT;
hw_cfg->gpio2.valid = true;
hw_cfg->valid = true;
return 0;
}
/*
* Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
@ -43,44 +337,6 @@ static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *phy
return 0;
}
/*
* Device 103C89C6 does have _DSD, however it is setup to use the wrong boost type.
* We can override the _DSD to correct the boost type here.
* Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists
* in the ACPI.
*/
static int hp_vision_acpi_fix(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
const char *hid)
{
struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);
cs35l41->index = id;
cs35l41->channel_index = 0;
/*
* This system has _DSD, it just contains an error, so we can still get the reset using
* the "reset" label.
*/
cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
cs35l41->index, GPIOD_OUT_LOW,
"cs35l41-reset");
cs35l41->speaker_id = -ENOENT;
hw_cfg->spk_pos = cs35l41->index ? 0 : 1; // right:left
hw_cfg->gpio1.func = CS35L41_NOT_USED;
hw_cfg->gpio1.valid = true;
hw_cfg->gpio2.func = CS35L41_INTERRUPT;
hw_cfg->gpio2.valid = true;
hw_cfg->bst_type = CS35L41_INT_BOOST;
hw_cfg->bst_ind = 1000;
hw_cfg->bst_ipk = 4500;
hw_cfg->bst_cap = 24;
hw_cfg->valid = true;
return 0;
}
struct cs35l41_prop_model {
const char *hid;
const char *ssid;
@ -91,7 +347,40 @@ struct cs35l41_prop_model {
static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
{ "CLSA0100", NULL, lenovo_legion_no_acpi },
{ "CLSA0101", NULL, lenovo_legion_no_acpi },
{ "CSC3551", "103C89C6", hp_vision_acpi_fix },
{ "CSC3551", "10280B27", generic_dsd_config },
{ "CSC3551", "10280B28", generic_dsd_config },
{ "CSC3551", "10280BEB", generic_dsd_config },
{ "CSC3551", "10280C4D", generic_dsd_config },
{ "CSC3551", "103C89C6", generic_dsd_config },
{ "CSC3551", "104312AF", generic_dsd_config },
{ "CSC3551", "10431433", generic_dsd_config },
{ "CSC3551", "10431463", generic_dsd_config },
{ "CSC3551", "10431473", generic_dsd_config },
{ "CSC3551", "10431483", generic_dsd_config },
{ "CSC3551", "10431493", generic_dsd_config },
{ "CSC3551", "104314D3", generic_dsd_config },
{ "CSC3551", "104314E3", generic_dsd_config },
{ "CSC3551", "10431503", generic_dsd_config },
{ "CSC3551", "10431533", generic_dsd_config },
{ "CSC3551", "10431573", generic_dsd_config },
{ "CSC3551", "10431663", generic_dsd_config },
{ "CSC3551", "104316D3", generic_dsd_config },
{ "CSC3551", "104316F3", generic_dsd_config },
{ "CSC3551", "104317F3", generic_dsd_config },
{ "CSC3551", "10431863", generic_dsd_config },
{ "CSC3551", "104318D3", generic_dsd_config },
{ "CSC3551", "10431C9F", generic_dsd_config },
{ "CSC3551", "10431CAF", generic_dsd_config },
{ "CSC3551", "10431CCF", generic_dsd_config },
{ "CSC3551", "10431CDF", generic_dsd_config },
{ "CSC3551", "10431CEF", generic_dsd_config },
{ "CSC3551", "10431D1F", generic_dsd_config },
{ "CSC3551", "10431DA2", generic_dsd_config },
{ "CSC3551", "10431E02", generic_dsd_config },
{ "CSC3551", "10431EE2", generic_dsd_config },
{ "CSC3551", "10431F12", generic_dsd_config },
{ "CSC3551", "10431F1F", generic_dsd_config },
{ "CSC3551", "10431F62", generic_dsd_config },
{}
};
@ -104,7 +393,7 @@ int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physd
if (!strcmp(model->hid, hid) &&
(!model->ssid ||
(cs35l41->acpi_subsystem_id &&
!strcmp(model->ssid, cs35l41->acpi_subsystem_id))))
!strcasecmp(model->ssid, cs35l41->acpi_subsystem_id))))
return model->add_prop(cs35l41, physdev, id, hid);
}

View File

@ -26,7 +26,7 @@ static int cs35l41_hda_spi_probe(struct spi_device *spi)
return -ENODEV;
return cs35l41_hda_probe(&spi->dev, device_name, spi_get_chipselect(spi, 0), spi->irq,
devm_regmap_init_spi(spi, &cs35l41_regmap_spi));
devm_regmap_init_spi(spi, &cs35l41_regmap_spi), SPI);
}
static void cs35l41_hda_spi_remove(struct spi_device *spi)

View File

@ -21,6 +21,10 @@ static int cs35l56_hda_spi_probe(struct spi_device *spi)
return -ENOMEM;
cs35l56->base.dev = &spi->dev;
#ifdef CS35L56_WAKE_HOLD_TIME_US
cs35l56->base.can_hibernate = true;
#endif
cs35l56->base.regmap = devm_regmap_init_spi(spi, &cs35l56_regmap_spi);
if (IS_ERR(cs35l56->base.regmap)) {
ret = PTR_ERR(cs35l56->base.regmap);

View File

@ -2242,6 +2242,8 @@ static const struct snd_pci_quirk power_save_denylist[] = {
SND_PCI_QUIRK(0x17aa, 0x36a7, "Lenovo C50 All in one", 0),
/* https://bugs.launchpad.net/bugs/1821663 */
SND_PCI_QUIRK(0x1631, 0xe017, "Packard Bell NEC IMEDIA 5204", 0),
/* KONTRON SinglePC may cause a stall at runtime resume */
SND_PCI_QUIRK(0x1734, 0x1232, "KONTRON SinglePC", 0),
{}
};
#endif /* CONFIG_PM */

View File

@ -1993,7 +1993,10 @@ static const struct snd_pci_quirk force_connect_list[] = {
SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x8715, "HP", 1),
SND_PCI_QUIRK(0x1043, 0x86ae, "ASUS", 1), /* Z170 PRO */
SND_PCI_QUIRK(0x1043, 0x86c7, "ASUS", 1), /* Z170M PLUS */
SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1),
SND_PCI_QUIRK(0x8086, 0x2060, "Intel NUC5CPYB", 1),
SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1),
{}
};

View File

@ -1987,6 +1987,7 @@ enum {
ALC887_FIXUP_ASUS_AUDIO,
ALC887_FIXUP_ASUS_HMIC,
ALCS1200A_FIXUP_MIC_VREF,
ALC888VD_FIXUP_MIC_100VREF,
};
static void alc889_fixup_coef(struct hda_codec *codec,
@ -2540,6 +2541,13 @@ static const struct hda_fixup alc882_fixups[] = {
{}
}
},
[ALC888VD_FIXUP_MIC_100VREF] = {
.type = HDA_FIXUP_PINCTLS,
.v.pins = (const struct hda_pintbl[]) {
{ 0x18, PIN_VREF100 }, /* headset mic */
{}
}
},
};
static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@ -2609,6 +2617,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF),
SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
@ -3256,6 +3265,7 @@ static void alc_disable_headset_jack_key(struct hda_codec *codec)
case 0x10ec0230:
case 0x10ec0236:
case 0x10ec0256:
case 0x10ec0257:
case 0x19e58326:
alc_write_coef_idx(codec, 0x48, 0x0);
alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
@ -3285,6 +3295,7 @@ static void alc_enable_headset_jack_key(struct hda_codec *codec)
case 0x10ec0230:
case 0x10ec0236:
case 0x10ec0256:
case 0x10ec0257:
case 0x19e58326:
alc_write_coef_idx(codec, 0x48, 0xd011);
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
@ -6496,6 +6507,7 @@ static void alc_combo_jack_hp_jd_restart(struct hda_codec *codec)
case 0x10ec0236:
case 0x10ec0255:
case 0x10ec0256:
case 0x10ec0257:
case 0x19e58326:
alc_update_coef_idx(codec, 0x1b, 0x8000, 1 << 15); /* Reset HP JD */
alc_update_coef_idx(codec, 0x1b, 0x8000, 0 << 15);
@ -6944,6 +6956,11 @@ static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup
cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 2);
}
static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 4);
}
static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action)
{
cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 2);
@ -7429,6 +7446,7 @@ enum {
ALC287_FIXUP_LEGION_16ACHG6,
ALC287_FIXUP_CS35L41_I2C_2,
ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED,
ALC287_FIXUP_CS35L41_I2C_4,
ALC245_FIXUP_CS35L41_SPI_2,
ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED,
ALC245_FIXUP_CS35L41_SPI_4,
@ -9415,6 +9433,10 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC285_FIXUP_HP_MUTE_LED,
},
[ALC287_FIXUP_CS35L41_I2C_4] = {
.type = HDA_FIXUP_FUNC,
.v.func = cs35l41_fixup_i2c_four,
},
[ALC245_FIXUP_CS35L41_SPI_2] = {
.type = HDA_FIXUP_FUNC,
.v.func = cs35l41_fixup_spi_two,
@ -9691,8 +9713,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0a9e, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0b19, "Dell XPS 15 9520", ALC289_FIXUP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
SND_PCI_QUIRK(0x1028, 0x0b27, "Dell", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1028, 0x0b28, "Dell", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
SND_PCI_QUIRK(0x1028, 0x0beb, "Dell XPS 15 9530 (2023)", ALC289_FIXUP_DELL_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
@ -9700,6 +9725,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0c1c, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1d, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c1e, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
SND_PCI_QUIRK(0x1028, 0x0c4d, "Dell", ALC287_FIXUP_CS35L41_I2C_4),
SND_PCI_QUIRK(0x1028, 0x0cbd, "Dell Oasis 13 CS MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1028, 0x0cbe, "Dell Oasis 13 2-IN-1 MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1028, 0x0cbf, "Dell Oasis 13 Low Weight MTU-L", ALC289_FIXUP_DELL_CS35L41_SPI_2),
@ -9782,6 +9808,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x83b9, "HP Spectre x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x841c, "HP Pavilion 15-CK0xx", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x84ae, "HP 15-db0403ng", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN),
SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360),
@ -9934,23 +9961,31 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650P", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604V", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603V", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601V", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X/GA402N", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604VI/VC/VE/VG/VJ/VQ/VU/VV/VY/VZ", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603VQ/VU/VV/VJ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601VV/VU/VJ/VQ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G614JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS G513PI/PU/PV", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1503, "ASUS G733PY/PZ/PZV/PYV", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301V", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x16d3, "ASUS UX5304VA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS UX7602VI/BZ", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS),
SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally RC71L_RC71L", ALC294_FIXUP_ASUS_ALLY),
SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY),
SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC294_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1970, "ASUS UX550VE", ALC289_FIXUP_ASUS_GA401),
@ -9972,23 +10007,30 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1c43, "ASUS UX8406MA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS),
SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JI", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JU/JV/JI", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JY/JZ/JI/JG", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x1d1f, "ASUS ROG Strix G17 2023 (G713PV)", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1ccf, "ASUS G814JU/JV/JI", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1cdf, "ASUS G814JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1cef, "ASUS G834JY/JZ/JI/JG", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1d1f, "ASUS G713PI/PU/PV/PVN", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS),
SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1f1f, "ASUS H7604JI/JV/J3D", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2),
SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401),
SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC245_FIXUP_CS35L41_SPI_2),
@ -10192,6 +10234,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3881, "YB9 dual power mode2 YC", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3882, "Lenovo Yoga Pro 7 14APH8", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
SND_PCI_QUIRK(0x17aa, 0x3884, "Y780 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C),
@ -10259,6 +10302,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10),
SND_PCI_QUIRK(0x8086, 0x3038, "Intel NUC 13", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0xf111, 0x0001, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0xf111, 0x0005, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0xf111, 0x0006, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
#if 0
/* Below is a quirk table taken from the old code.
@ -12184,6 +12229,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN),
SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),

View File

@ -65,6 +65,15 @@ enum calib_data {
CALIB_MAX
};
struct tas2781_hda {
struct device *dev;
struct tasdevice_priv *priv;
struct snd_kcontrol *dsp_prog_ctl;
struct snd_kcontrol *dsp_conf_ctl;
struct snd_kcontrol *prof_ctl;
struct snd_kcontrol *snd_ctls[3];
};
static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
{
struct tasdevice_priv *tas_priv = data;
@ -125,26 +134,26 @@ err:
static void tas2781_hda_playback_hook(struct device *dev, int action)
{
struct tasdevice_priv *tas_priv = dev_get_drvdata(dev);
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
dev_dbg(tas_priv->dev, "%s: action = %d\n", __func__, action);
dev_dbg(tas_hda->dev, "%s: action = %d\n", __func__, action);
switch (action) {
case HDA_GEN_PCM_ACT_OPEN:
pm_runtime_get_sync(dev);
mutex_lock(&tas_priv->codec_lock);
tasdevice_tuning_switch(tas_priv, 0);
mutex_unlock(&tas_priv->codec_lock);
mutex_lock(&tas_hda->priv->codec_lock);
tasdevice_tuning_switch(tas_hda->priv, 0);
mutex_unlock(&tas_hda->priv->codec_lock);
break;
case HDA_GEN_PCM_ACT_CLOSE:
mutex_lock(&tas_priv->codec_lock);
tasdevice_tuning_switch(tas_priv, 1);
mutex_unlock(&tas_priv->codec_lock);
mutex_lock(&tas_hda->priv->codec_lock);
tasdevice_tuning_switch(tas_hda->priv, 1);
mutex_unlock(&tas_hda->priv->codec_lock);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
break;
default:
dev_dbg(tas_priv->dev, "Playback action not supported: %d\n",
dev_dbg(tas_hda->dev, "Playback action not supported: %d\n",
action);
break;
}
@ -421,9 +430,9 @@ static void tas2781_apply_calib(struct tasdevice_priv *tas_priv)
}
}
/* Update the calibrate data, including speaker impedance, f0, etc, into algo.
/* Update the calibration data, including speaker impedance, f0, etc, into algo.
* Calibrate data is done by manufacturer in the factory. These data are used
* by Algo for calucating the speaker temperature, speaker membrance excursion
* by Algo for calculating the speaker temperature, speaker membrane excursion
* and f0 in real time during playback.
*/
static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
@ -455,9 +464,9 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
status = efi.get_variable(efi_name, &efi_guid, &attr,
&tas_priv->cali_data.total_sz,
tas_priv->cali_data.data);
if (status != EFI_SUCCESS)
return -EINVAL;
}
if (status != EFI_SUCCESS)
return -EINVAL;
tmp_val = (unsigned int *)tas_priv->cali_data.data;
@ -477,9 +486,28 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
return 0;
}
static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
{
struct hda_codec *codec = tas_hda->priv->codec;
if (tas_hda->dsp_prog_ctl)
snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
if (tas_hda->dsp_conf_ctl)
snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--)
if (tas_hda->snd_ctls[i])
snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]);
if (tas_hda->prof_ctl)
snd_ctl_remove(codec->card, tas_hda->prof_ctl);
}
static void tasdev_fw_ready(const struct firmware *fmw, void *context)
{
struct tasdevice_priv *tas_priv = context;
struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
struct hda_codec *codec = tas_priv->codec;
int i, ret;
@ -490,8 +518,8 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
if (ret)
goto out;
ret = snd_ctl_add(codec->card,
snd_ctl_new1(&tas2781_prof_ctrl, tas_priv));
tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl, tas_priv);
ret = snd_ctl_add(codec->card, tas_hda->prof_ctl);
if (ret) {
dev_err(tas_priv->dev,
"Failed to add KControl %s = %d\n",
@ -500,8 +528,9 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
}
for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) {
ret = snd_ctl_add(codec->card,
snd_ctl_new1(&tas2781_snd_controls[i], tas_priv));
tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i],
tas_priv);
ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]);
if (ret) {
dev_err(tas_priv->dev,
"Failed to add KControl %s = %d\n",
@ -523,8 +552,9 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
goto out;
}
ret = snd_ctl_add(codec->card,
snd_ctl_new1(&tas2781_dsp_prog_ctrl, tas_priv));
tas_hda->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_prog_ctrl,
tas_priv);
ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl);
if (ret) {
dev_err(tas_priv->dev,
"Failed to add KControl %s = %d\n",
@ -532,8 +562,9 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
goto out;
}
ret = snd_ctl_add(codec->card,
snd_ctl_new1(&tas2781_dsp_conf_ctrl, tas_priv));
tas_hda->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_conf_ctrl,
tas_priv);
ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl);
if (ret) {
dev_err(tas_priv->dev,
"Failed to add KControl %s = %d\n",
@ -543,6 +574,10 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
tasdevice_prmg_load(tas_priv, 0);
if (tas_priv->fmw->nr_programs > 0)
tas_priv->cur_prog = 0;
if (tas_priv->fmw->nr_configurations > 0)
tas_priv->cur_conf = 0;
/* If calibrated data occurs error, dsp will still works with default
* calibrated data inside algo.
@ -550,32 +585,27 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
tas2781_save_calibration(tas_priv);
out:
if (tas_priv->fw_state == TASDEVICE_DSP_FW_FAIL) {
/*If DSP FW fail, kcontrol won't be created */
tasdevice_config_info_remove(tas_priv);
tasdevice_dsp_remove(tas_priv);
}
mutex_unlock(&tas_priv->codec_lock);
mutex_unlock(&tas_hda->priv->codec_lock);
if (fmw)
release_firmware(fmw);
pm_runtime_mark_last_busy(tas_priv->dev);
pm_runtime_put_autosuspend(tas_priv->dev);
pm_runtime_mark_last_busy(tas_hda->dev);
pm_runtime_put_autosuspend(tas_hda->dev);
}
static int tas2781_hda_bind(struct device *dev, struct device *master,
void *master_data)
{
struct tasdevice_priv *tas_priv = dev_get_drvdata(dev);
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
struct hda_component *comps = master_data;
struct hda_codec *codec;
unsigned int subid;
int ret;
if (!comps || tas_priv->index < 0 ||
tas_priv->index >= HDA_MAX_COMPONENTS)
if (!comps || tas_hda->priv->index < 0 ||
tas_hda->priv->index >= HDA_MAX_COMPONENTS)
return -EINVAL;
comps = &comps[tas_priv->index];
comps = &comps[tas_hda->priv->index];
if (comps->dev)
return -EBUSY;
@ -584,10 +614,10 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
switch (subid) {
case 0x17aa:
tas_priv->catlog_id = LENOVO;
tas_hda->priv->catlog_id = LENOVO;
break;
default:
tas_priv->catlog_id = OTHERS;
tas_hda->priv->catlog_id = OTHERS;
break;
}
@ -597,7 +627,7 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
strscpy(comps->name, dev_name(dev), sizeof(comps->name));
ret = tascodec_init(tas_priv, codec, tasdev_fw_ready);
ret = tascodec_init(tas_hda->priv, codec, tasdev_fw_ready);
if (!ret)
comps->playback_hook = tas2781_hda_playback_hook;
@ -610,16 +640,22 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
static void tas2781_hda_unbind(struct device *dev,
struct device *master, void *master_data)
{
struct tasdevice_priv *tas_priv = dev_get_drvdata(dev);
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
struct hda_component *comps = master_data;
comps = &comps[tas_hda->priv->index];
if (comps[tas_priv->index].dev == dev)
memset(&comps[tas_priv->index], 0, sizeof(*comps));
if (comps->dev == dev) {
comps->dev = NULL;
memset(comps->name, 0, sizeof(comps->name));
comps->playback_hook = NULL;
}
tasdevice_config_info_remove(tas_priv);
tasdevice_dsp_remove(tas_priv);
tas2781_hda_remove_controls(tas_hda);
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
tasdevice_config_info_remove(tas_hda->priv);
tasdevice_dsp_remove(tas_hda->priv);
tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING;
}
static const struct component_ops tas2781_hda_comp_ops = {
@ -629,21 +665,21 @@ static const struct component_ops tas2781_hda_comp_ops = {
static void tas2781_hda_remove(struct device *dev)
{
struct tasdevice_priv *tas_priv = dev_get_drvdata(dev);
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
pm_runtime_get_sync(tas_priv->dev);
pm_runtime_disable(tas_priv->dev);
pm_runtime_get_sync(tas_hda->dev);
pm_runtime_disable(tas_hda->dev);
component_del(tas_priv->dev, &tas2781_hda_comp_ops);
component_del(tas_hda->dev, &tas2781_hda_comp_ops);
pm_runtime_put_noidle(tas_priv->dev);
pm_runtime_put_noidle(tas_hda->dev);
tasdevice_remove(tas_priv);
tasdevice_remove(tas_hda->priv);
}
static int tas2781_hda_i2c_probe(struct i2c_client *clt)
{
struct tasdevice_priv *tas_priv;
struct tas2781_hda *tas_hda;
const char *device_name;
int ret;
@ -652,37 +688,44 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
else
return -ENODEV;
tas_priv = tasdevice_kzalloc(clt);
if (!tas_priv)
tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL);
if (!tas_hda)
return -ENOMEM;
tas_priv->irq_info.irq = clt->irq;
ret = tas2781_read_acpi(tas_priv, device_name);
dev_set_drvdata(&clt->dev, tas_hda);
tas_hda->dev = &clt->dev;
tas_hda->priv = tasdevice_kzalloc(clt);
if (!tas_hda->priv)
return -ENOMEM;
tas_hda->priv->irq_info.irq = clt->irq;
ret = tas2781_read_acpi(tas_hda->priv, device_name);
if (ret)
return dev_err_probe(tas_priv->dev, ret,
return dev_err_probe(tas_hda->dev, ret,
"Platform not supported\n");
ret = tasdevice_init(tas_priv);
ret = tasdevice_init(tas_hda->priv);
if (ret)
goto err;
pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000);
pm_runtime_use_autosuspend(tas_priv->dev);
pm_runtime_mark_last_busy(tas_priv->dev);
pm_runtime_set_active(tas_priv->dev);
pm_runtime_get_noresume(tas_priv->dev);
pm_runtime_enable(tas_priv->dev);
pm_runtime_set_autosuspend_delay(tas_hda->dev, 3000);
pm_runtime_use_autosuspend(tas_hda->dev);
pm_runtime_mark_last_busy(tas_hda->dev);
pm_runtime_set_active(tas_hda->dev);
pm_runtime_get_noresume(tas_hda->dev);
pm_runtime_enable(tas_hda->dev);
pm_runtime_put_autosuspend(tas_priv->dev);
pm_runtime_put_autosuspend(tas_hda->dev);
ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops);
tas2781_reset(tas_hda->priv);
ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops);
if (ret) {
dev_err(tas_priv->dev, "Register component failed: %d\n", ret);
pm_runtime_disable(tas_priv->dev);
goto err;
dev_err(tas_hda->dev, "Register component failed: %d\n", ret);
pm_runtime_disable(tas_hda->dev);
}
tas2781_reset(tas_priv);
err:
if (ret)
tas2781_hda_remove(&clt->dev);
@ -696,81 +739,65 @@ static void tas2781_hda_i2c_remove(struct i2c_client *clt)
static int tas2781_runtime_suspend(struct device *dev)
{
struct tasdevice_priv *tas_priv = dev_get_drvdata(dev);
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
int i;
dev_dbg(tas_priv->dev, "Runtime Suspend\n");
dev_dbg(tas_hda->dev, "Runtime Suspend\n");
mutex_lock(&tas_priv->codec_lock);
mutex_lock(&tas_hda->priv->codec_lock);
if (tas_priv->playback_started) {
tasdevice_tuning_switch(tas_priv, 1);
tas_priv->playback_started = false;
if (tas_hda->priv->playback_started) {
tasdevice_tuning_switch(tas_hda->priv, 1);
tas_hda->priv->playback_started = false;
}
for (i = 0; i < tas_priv->ndev; i++) {
tas_priv->tasdevice[i].cur_book = -1;
tas_priv->tasdevice[i].cur_prog = -1;
tas_priv->tasdevice[i].cur_conf = -1;
for (i = 0; i < tas_hda->priv->ndev; i++) {
tas_hda->priv->tasdevice[i].cur_book = -1;
tas_hda->priv->tasdevice[i].cur_prog = -1;
tas_hda->priv->tasdevice[i].cur_conf = -1;
}
regcache_cache_only(tas_priv->regmap, true);
regcache_mark_dirty(tas_priv->regmap);
mutex_unlock(&tas_priv->codec_lock);
mutex_unlock(&tas_hda->priv->codec_lock);
return 0;
}
static int tas2781_runtime_resume(struct device *dev)
{
struct tasdevice_priv *tas_priv = dev_get_drvdata(dev);
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
unsigned long calib_data_sz =
tas_priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE;
int ret;
tas_hda->priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE;
dev_dbg(tas_priv->dev, "Runtime Resume\n");
dev_dbg(tas_hda->dev, "Runtime Resume\n");
mutex_lock(&tas_priv->codec_lock);
mutex_lock(&tas_hda->priv->codec_lock);
regcache_cache_only(tas_priv->regmap, false);
ret = regcache_sync(tas_priv->regmap);
if (ret) {
dev_err(tas_priv->dev,
"Failed to restore register cache: %d\n", ret);
goto out;
}
tasdevice_prmg_load(tas_priv, tas_priv->cur_prog);
tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
/* If calibrated data occurs error, dsp will still works with default
* calibrated data inside algo.
*/
if (tas_priv->cali_data.total_sz > calib_data_sz)
tas2781_apply_calib(tas_priv);
if (tas_hda->priv->cali_data.total_sz > calib_data_sz)
tas2781_apply_calib(tas_hda->priv);
out:
mutex_unlock(&tas_priv->codec_lock);
mutex_unlock(&tas_hda->priv->codec_lock);
return ret;
return 0;
}
static int tas2781_system_suspend(struct device *dev)
{
struct tasdevice_priv *tas_priv = dev_get_drvdata(dev);
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
int ret;
dev_dbg(tas_priv->dev, "System Suspend\n");
dev_dbg(tas_hda->priv->dev, "System Suspend\n");
ret = pm_runtime_force_suspend(dev);
if (ret)
return ret;
/* Shutdown chip before system suspend */
regcache_cache_only(tas_priv->regmap, false);
tasdevice_tuning_switch(tas_priv, 1);
regcache_cache_only(tas_priv->regmap, true);
regcache_mark_dirty(tas_priv->regmap);
tasdevice_tuning_switch(tas_hda->priv, 1);
/*
* Reset GPIO may be shared, so cannot reset here.
@ -781,33 +808,33 @@ static int tas2781_system_suspend(struct device *dev)
static int tas2781_system_resume(struct device *dev)
{
struct tasdevice_priv *tas_priv = dev_get_drvdata(dev);
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
unsigned long calib_data_sz =
tas_priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE;
tas_hda->priv->ndev * TASDEVICE_SPEAKER_CALIBRATION_SIZE;
int i, ret;
dev_dbg(tas_priv->dev, "System Resume\n");
dev_info(tas_hda->priv->dev, "System Resume\n");
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
mutex_lock(&tas_priv->codec_lock);
mutex_lock(&tas_hda->priv->codec_lock);
for (i = 0; i < tas_priv->ndev; i++) {
tas_priv->tasdevice[i].cur_book = -1;
tas_priv->tasdevice[i].cur_prog = -1;
tas_priv->tasdevice[i].cur_conf = -1;
for (i = 0; i < tas_hda->priv->ndev; i++) {
tas_hda->priv->tasdevice[i].cur_book = -1;
tas_hda->priv->tasdevice[i].cur_prog = -1;
tas_hda->priv->tasdevice[i].cur_conf = -1;
}
tas2781_reset(tas_priv);
tasdevice_prmg_load(tas_priv, tas_priv->cur_prog);
tas2781_reset(tas_hda->priv);
tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
/* If calibrated data occurs error, dsp will still work with default
* calibrated data inside algo.
*/
if (tas_priv->cali_data.total_sz > calib_data_sz)
tas2781_apply_calib(tas_priv);
mutex_unlock(&tas_priv->codec_lock);
if (tas_hda->priv->cali_data.total_sz > calib_data_sz)
tas2781_apply_calib(tas_hda->priv);
mutex_unlock(&tas_hda->priv->codec_lock);
return 0;
}

View File

@ -103,6 +103,20 @@ static const struct config_entry config_table[] = {
{}
},
},
{
.flags = FLAG_AMD_LEGACY,
.device = ACP_PCI_DEV_ID,
.dmi_table = (const struct dmi_system_id []) {
{
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "HUAWEI"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HVY-WXX9"),
DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "M1010"),
},
},
{}
},
},
{
.flags = FLAG_AMD_LEGACY,
.device = ACP_PCI_DEV_ID,

View File

@ -283,6 +283,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "M6500RC"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "E1504FA"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
@ -367,6 +374,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "8A3E"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
DMI_MATCH(DMI_BOARD_NAME, "8B2F"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
@ -381,6 +395,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "pang12"),
}
},
{
.driver_data = &acp6x_card,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "System76"),
DMI_MATCH(DMI_PRODUCT_VERSION, "pang13"),
}
},
{}
};

View File

@ -62,7 +62,7 @@ static struct i2c_driver cs35l45_i2c_driver = {
.driver = {
.name = "cs35l45",
.of_match_table = cs35l45_of_match,
.pm = &cs35l45_pm_ops,
.pm = pm_ptr(&cs35l45_pm_ops),
},
.id_table = cs35l45_id_i2c,
.probe = cs35l45_i2c_probe,

View File

@ -64,7 +64,7 @@ static struct spi_driver cs35l45_spi_driver = {
.driver = {
.name = "cs35l45",
.of_match_table = cs35l45_of_match,
.pm = &cs35l45_pm_ops,
.pm = pm_ptr(&cs35l45_pm_ops),
},
.id_table = cs35l45_id_spi,
.probe = cs35l45_spi_probe,

View File

@ -947,6 +947,8 @@ static int cs35l45_enter_hibernate(struct cs35l45_private *cs35l45)
cs35l45_setup_hibernate(cs35l45);
regmap_set_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2, CS35L45_DSP_VIRT2_MBOX_MASK);
// Don't wait for ACK since bus activity would wake the device
regmap_write(cs35l45->regmap, CS35L45_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE);
@ -967,6 +969,8 @@ static int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45)
CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
if (!ret) {
dev_dbg(cs35l45->dev, "Wake success at cycle: %d\n", j);
regmap_clear_bits(cs35l45->regmap, CS35L45_IRQ1_MASK_2,
CS35L45_DSP_VIRT2_MBOX_MASK);
return 0;
}
usleep_range(100, 200);
@ -982,7 +986,7 @@ static int cs35l45_exit_hibernate(struct cs35l45_private *cs35l45)
return -ETIMEDOUT;
}
static int __maybe_unused cs35l45_runtime_suspend(struct device *dev)
static int cs35l45_runtime_suspend(struct device *dev)
{
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
@ -999,7 +1003,7 @@ static int __maybe_unused cs35l45_runtime_suspend(struct device *dev)
return 0;
}
static int __maybe_unused cs35l45_runtime_resume(struct device *dev)
static int cs35l45_runtime_resume(struct device *dev)
{
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
int ret;
@ -1026,6 +1030,46 @@ static int __maybe_unused cs35l45_runtime_resume(struct device *dev)
return ret;
}
static int cs35l45_sys_suspend(struct device *dev)
{
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
dev_dbg(cs35l45->dev, "System suspend, disabling IRQ\n");
disable_irq(cs35l45->irq);
return 0;
}
static int cs35l45_sys_suspend_noirq(struct device *dev)
{
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
dev_dbg(cs35l45->dev, "Late system suspend, reenabling IRQ\n");
enable_irq(cs35l45->irq);
return 0;
}
static int cs35l45_sys_resume_noirq(struct device *dev)
{
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
dev_dbg(cs35l45->dev, "Early system resume, disabling IRQ\n");
disable_irq(cs35l45->irq);
return 0;
}
static int cs35l45_sys_resume(struct device *dev)
{
struct cs35l45_private *cs35l45 = dev_get_drvdata(dev);
dev_dbg(cs35l45->dev, "System resume, reenabling IRQ\n");
enable_irq(cs35l45->irq);
return 0;
}
static int cs35l45_apply_property_config(struct cs35l45_private *cs35l45)
{
struct device_node *node = cs35l45->dev->of_node;
@ -1466,10 +1510,12 @@ void cs35l45_remove(struct cs35l45_private *cs35l45)
}
EXPORT_SYMBOL_NS_GPL(cs35l45_remove, SND_SOC_CS35L45);
const struct dev_pm_ops cs35l45_pm_ops = {
SET_RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL)
EXPORT_GPL_DEV_PM_OPS(cs35l45_pm_ops) = {
RUNTIME_PM_OPS(cs35l45_runtime_suspend, cs35l45_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend, cs35l45_sys_resume)
NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l45_sys_suspend_noirq, cs35l45_sys_resume_noirq)
};
EXPORT_SYMBOL_NS_GPL(cs35l45_pm_ops, SND_SOC_CS35L45);
MODULE_DESCRIPTION("ASoC CS35L45 driver");
MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, <james.schulman@cirrus.com>");

View File

@ -237,7 +237,7 @@ error:
return ret;
}
static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool force_high)
static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool type_detect)
{
struct cs42l43 *cs42l43 = priv->core;
unsigned int val = 0x3 << CS42L43_HSBIAS_MODE_SHIFT;
@ -247,16 +247,17 @@ static void cs42l43_start_hs_bias(struct cs42l43_codec *priv, bool force_high)
regmap_update_bits(cs42l43->regmap, CS42L43_HS2,
CS42L43_HS_CLAMP_DISABLE_MASK, CS42L43_HS_CLAMP_DISABLE_MASK);
if (!force_high && priv->bias_low)
val = 0x2 << CS42L43_HSBIAS_MODE_SHIFT;
if (!type_detect) {
if (priv->bias_low)
val = 0x2 << CS42L43_HSBIAS_MODE_SHIFT;
if (priv->bias_sense_ua) {
regmap_update_bits(cs42l43->regmap,
CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
CS42L43_HSBIAS_SENSE_EN_MASK |
CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,
CS42L43_HSBIAS_SENSE_EN_MASK |
CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);
if (priv->bias_sense_ua)
regmap_update_bits(cs42l43->regmap,
CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL,
CS42L43_HSBIAS_SENSE_EN_MASK |
CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK,
CS42L43_HSBIAS_SENSE_EN_MASK |
CS42L43_AUTO_HSBIAS_CLAMP_EN_MASK);
}
regmap_update_bits(cs42l43->regmap, CS42L43_MIC_DETECT_CONTROL_1,

View File

@ -578,7 +578,7 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk,
break;
case SND_SOC_DAIFMT_LEFT_J:
hi_size = bitwidth_sclk;
frm_delay = 2;
frm_delay = 0;
frm_phase = 1;
break;
case SND_SOC_DAIFMT_DSP_A:
@ -1682,7 +1682,7 @@ static ssize_t hpload_dc_r_show(struct device *dev,
return cs43130_show_dc(dev, buf, HP_RIGHT);
}
static u16 const cs43130_ac_freq[CS43130_AC_FREQ] = {
static const u16 cs43130_ac_freq[CS43130_AC_FREQ] = {
24,
43,
93,
@ -2362,7 +2362,7 @@ static const struct regmap_config cs43130_regmap = {
.use_single_write = true,
};
static u16 const cs43130_dc_threshold[CS43130_DC_THRESHOLD] = {
static const u16 cs43130_dc_threshold[CS43130_DC_THRESHOLD] = {
50,
120,
};

View File

@ -696,7 +696,7 @@ static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct device *dev)
aad_pdata->mic_det_thr =
da7219_aad_fw_mic_det_thr(dev, fw_val32);
else
aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS;
aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_200_OHMS;
if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0)
aad_pdata->jack_ins_deb =

View File

@ -132,6 +132,9 @@ static struct snd_soc_dai_driver hdac_hda_dais[] = {
.sig_bits = 24,
},
},
};
static struct snd_soc_dai_driver hdac_hda_hdmi_dais[] = {
{
.id = HDAC_HDMI_0_DAI_ID,
.name = "intel-hdmi-hifi1",
@ -605,8 +608,16 @@ static const struct snd_soc_component_driver hdac_hda_codec = {
.endianness = 1,
};
static const struct snd_soc_component_driver hdac_hda_hdmi_codec = {
.probe = hdac_hda_codec_probe,
.remove = hdac_hda_codec_remove,
.idle_bias_on = false,
.endianness = 1,
};
static int hdac_hda_dev_probe(struct hdac_device *hdev)
{
struct hdac_hda_priv *hda_pvt = dev_get_drvdata(&hdev->dev);
struct hdac_ext_link *hlink;
int ret;
@ -619,9 +630,15 @@ static int hdac_hda_dev_probe(struct hdac_device *hdev)
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
/* ASoC specific initialization */
ret = devm_snd_soc_register_component(&hdev->dev,
&hdac_hda_codec, hdac_hda_dais,
ARRAY_SIZE(hdac_hda_dais));
if (hda_pvt->need_display_power)
ret = devm_snd_soc_register_component(&hdev->dev,
&hdac_hda_hdmi_codec, hdac_hda_hdmi_dais,
ARRAY_SIZE(hdac_hda_hdmi_dais));
else
ret = devm_snd_soc_register_component(&hdev->dev,
&hdac_hda_codec, hdac_hda_dais,
ARRAY_SIZE(hdac_hda_dais));
if (ret < 0) {
dev_err(&hdev->dev, "failed to register HDA codec %d\n", ret);
return ret;

View File

@ -850,8 +850,9 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai)
static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp,
unsigned int jack_status)
{
if (hcp->jack && jack_status != hcp->jack_status) {
snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT);
if (jack_status != hcp->jack_status) {
if (hcp->jack)
snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT);
hcp->jack_status = jack_status;
}
}
@ -880,6 +881,13 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component,
if (hcp->hcd.ops->hook_plugged_cb) {
hcp->jack = jack;
/*
* Report the initial jack status which may have been provided
* by the parent hdmi driver while the hpd hook was registered.
*/
snd_soc_jack_report(jack, hcp->jack_status, SND_JACK_LINEOUT);
return 0;
}

View File

@ -2021,6 +2021,11 @@ static int tx_macro_probe(struct platform_device *pdev)
tx->dev = dev;
/* Set active_decimator default value */
tx->active_decimator[TX_MACRO_AIF1_CAP] = -1;
tx->active_decimator[TX_MACRO_AIF2_CAP] = -1;
tx->active_decimator[TX_MACRO_AIF3_CAP] = -1;
/* set MCLK and NPL rates */
clk_set_rate(tx->mclk, MCLK_FREQ);
clk_set_rate(tx->npl, MCLK_FREQ);

View File

@ -184,6 +184,7 @@ static int nau8822_eq_get(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *params = (void *)kcontrol->private_value;
int i, reg;
u16 reg_val, *val;
__be16 tmp;
val = (u16 *)ucontrol->value.bytes.data;
reg = NAU8822_REG_EQ1;
@ -192,8 +193,8 @@ static int nau8822_eq_get(struct snd_kcontrol *kcontrol,
/* conversion of 16-bit integers between native CPU format
* and big endian format
*/
reg_val = cpu_to_be16(reg_val);
memcpy(val + i, &reg_val, sizeof(reg_val));
tmp = cpu_to_be16(reg_val);
memcpy(val + i, &tmp, sizeof(tmp));
}
return 0;
@ -216,6 +217,7 @@ static int nau8822_eq_put(struct snd_kcontrol *kcontrol,
void *data;
u16 *val, value;
int i, reg, ret;
__be16 *tmp;
data = kmemdup(ucontrol->value.bytes.data,
params->max, GFP_KERNEL | GFP_DMA);
@ -228,7 +230,8 @@ static int nau8822_eq_put(struct snd_kcontrol *kcontrol,
/* conversion of 16-bit integers between native CPU format
* and big endian format
*/
value = be16_to_cpu(*(val + i));
tmp = (__be16 *)(val + i);
value = be16_to_cpup(tmp);
ret = snd_soc_component_write(component, reg + i, value);
if (ret) {
dev_err(component->dev,

View File

@ -448,6 +448,7 @@ struct rt5645_priv {
struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
struct rt5645_eq_param_s *eq_param;
struct timer_list btn_check_timer;
struct mutex jd_mutex;
int codec_type;
int sysclk;
@ -3193,6 +3194,8 @@ static int rt5645_jack_detect(struct snd_soc_component *component, int jack_inse
rt5645_enable_push_button_irq(component, true);
}
} else {
if (rt5645->en_button_func)
rt5645_enable_push_button_irq(component, false);
snd_soc_dapm_disable_pin(dapm, "Mic Det Power");
snd_soc_dapm_sync(dapm);
rt5645->jack_type = SND_JACK_HEADPHONE;
@ -3295,6 +3298,8 @@ static void rt5645_jack_detect_work(struct work_struct *work)
if (!rt5645->component)
return;
mutex_lock(&rt5645->jd_mutex);
switch (rt5645->pdata.jd_mode) {
case 0: /* Not using rt5645 JD */
if (rt5645->gpiod_hp_det) {
@ -3321,7 +3326,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
if (!val && (rt5645->jack_type == 0)) { /* jack in */
report = rt5645_jack_detect(rt5645->component, 1);
} else if (!val && rt5645->jack_type != 0) {
} else if (!val && rt5645->jack_type == SND_JACK_HEADSET) {
/* for push button and jack out */
btn_type = 0;
if (snd_soc_component_read(rt5645->component, RT5645_INT_IRQ_ST) & 0x4) {
@ -3377,6 +3382,8 @@ static void rt5645_jack_detect_work(struct work_struct *work)
rt5645_jack_detect(rt5645->component, 0);
}
mutex_unlock(&rt5645->jd_mutex);
snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE);
if (rt5645->en_button_func)
@ -4150,6 +4157,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c)
}
timer_setup(&rt5645->btn_check_timer, rt5645_btn_check_callback, 0);
mutex_init(&rt5645->jd_mutex);
INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work);

View File

@ -39,7 +39,7 @@ static const struct regmap_range_cfg tasdevice_ranges[] = {
static const struct regmap_config tasdevice_regmap = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
.cache_type = REGCACHE_NONE,
.ranges = tasdevice_ranges,
.num_ranges = ARRAY_SIZE(tasdevice_ranges),
.max_register = 256 * 128,
@ -316,8 +316,6 @@ int tasdevice_init(struct tasdevice_priv *tas_priv)
tas_priv->tasdevice[i].cur_conf = -1;
}
dev_set_drvdata(tas_priv->dev, tas_priv);
mutex_init(&tas_priv->codec_lock);
out:

View File

@ -2189,11 +2189,11 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no,
goto out;
}
conf = &(tas_fmw->configs[cfg_no]);
for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) {
if (cfg_info[rca_conf_no]->active_dev & (1 << i)) {
if (tas_priv->tasdevice[i].cur_prog != prm_no
|| tas_priv->force_fwload_status) {
if (prm_no >= 0
&& (tas_priv->tasdevice[i].cur_prog != prm_no
|| tas_priv->force_fwload_status)) {
tas_priv->tasdevice[i].cur_conf = -1;
tas_priv->tasdevice[i].is_loading = true;
prog_status++;
@ -2228,7 +2228,8 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no,
}
for (i = 0, status = 0; i < tas_priv->ndev; i++) {
if (tas_priv->tasdevice[i].cur_conf != cfg_no
if (cfg_no >= 0
&& tas_priv->tasdevice[i].cur_conf != cfg_no
&& (cfg_info[rca_conf_no]->active_dev & (1 << i))
&& (tas_priv->tasdevice[i].is_loaderr == false)) {
status++;
@ -2238,6 +2239,7 @@ int tasdevice_select_tuningprm_cfg(void *context, int prm_no,
}
if (status) {
conf = &(tas_fmw->configs[cfg_no]);
status = 0;
tasdevice_load_data(tas_priv, &(conf->dev_data));
for (i = 0; i < tas_priv->ndev; i++) {
@ -2281,7 +2283,7 @@ int tasdevice_prmg_load(void *context, int prm_no)
}
for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) {
if (tas_priv->tasdevice[i].cur_prog != prm_no) {
if (prm_no >= 0 && tas_priv->tasdevice[i].cur_prog != prm_no) {
tas_priv->tasdevice[i].cur_conf = -1;
tas_priv->tasdevice[i].is_loading = true;
prog_status++;
@ -2326,7 +2328,7 @@ int tasdevice_prmg_calibdata_load(void *context, int prm_no)
}
for (i = 0, prog_status = 0; i < tas_priv->ndev; i++) {
if (tas_priv->tasdevice[i].cur_prog != prm_no) {
if (prm_no >= 0 && tas_priv->tasdevice[i].cur_prog != prm_no) {
tas_priv->tasdevice[i].cur_conf = -1;
tas_priv->tasdevice[i].is_loading = true;
prog_status++;

View File

@ -689,6 +689,8 @@ static int tasdevice_i2c_probe(struct i2c_client *i2c)
if (!tas_priv)
return -ENOMEM;
dev_set_drvdata(&i2c->dev, tas_priv);
if (ACPI_HANDLE(&i2c->dev)) {
acpi_id = acpi_match_device(i2c->dev.driver->acpi_match_table,
&i2c->dev);

View File

@ -186,7 +186,7 @@ SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_MONOMIX, 0, 1, 0),
/* Boost mixer */
static const struct snd_kcontrol_new wm8974_boost_mixer[] = {
SOC_DAPM_SINGLE("Aux Switch", WM8974_INPPGA, 6, 1, 1),
SOC_DAPM_SINGLE("PGA Switch", WM8974_INPPGA, 6, 1, 1),
};
/* Input PGA */
@ -246,8 +246,8 @@ static const struct snd_soc_dapm_route wm8974_dapm_routes[] = {
/* Boost Mixer */
{"ADC", NULL, "Boost Mixer"},
{"Boost Mixer", "Aux Switch", "Aux Input"},
{"Boost Mixer", NULL, "Input PGA"},
{"Boost Mixer", NULL, "Aux Input"},
{"Boost Mixer", "PGA Switch", "Input PGA"},
{"Boost Mixer", NULL, "MICP"},
/* Input PGA */

View File

@ -1451,12 +1451,12 @@ static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset,
&region->base_addr);
if (ret < 0)
return ret;
goto err;
ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset,
&offset);
if (ret < 0)
return ret;
goto err;
region->cumulative_size = offset;
@ -1467,6 +1467,10 @@ static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf)
}
return 0;
err:
kfree(buf->regions);
return ret;
}
static void wm_adsp_buffer_clear(struct wm_adsp_compr_buf *buf)

View File

@ -360,6 +360,7 @@ config SND_SOC_IMX_HDMI
config SND_SOC_IMX_RPMSG
tristate "SoC Audio support for i.MX boards with rpmsg"
depends on RPMSG
depends on OF && I2C
select SND_SOC_IMX_PCM_RPMSG
select SND_SOC_IMX_AUDIO_RPMSG
help

View File

@ -673,6 +673,20 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
FSL_SAI_CR3_TRCE_MASK,
FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask)));
/*
* When the TERE and FSD_MSTR enabled before configuring the word width
* There will be no frame sync clock issue, because word width impact
* the generation of frame sync clock.
*
* TERE enabled earlier only for i.MX8MP case for the hardware limitation,
* We need to disable FSD_MSTR before configuring word width, then enable
* FSD_MSTR bit for this specific case.
*/
if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output &&
!sai->is_consumer_mode)
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
FSL_SAI_CR4_FSD_MSTR, 0);
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
FSL_SAI_CR4_CHMOD_MASK,
@ -680,6 +694,13 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs),
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
FSL_SAI_CR5_FBT_MASK, val_cr5);
/* Enable FSD_MSTR after configuring word width */
if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output &&
!sai->is_consumer_mode)
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR);
regmap_write(sai->regmap, FSL_SAI_xMR(tx),
~0UL - ((1 << min(channels, slots)) - 1));
@ -693,6 +714,9 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int ofs = sai->soc_data->reg_offset;
/* Clear xMR to avoid channel swap with mclk_with_tere enabled case */
regmap_write(sai->regmap, FSL_SAI_xMR(tx), 0);
regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
FSL_SAI_CR3_TRCE_MASK, 0);

View File

@ -358,7 +358,7 @@ static int fsl_xcvr_en_aud_pll(struct fsl_xcvr *xcvr, u32 freq)
struct device *dev = &xcvr->pdev->dev;
int ret;
freq = xcvr->soc_data->spdif_only ? freq / 10 : freq;
freq = xcvr->soc_data->spdif_only ? freq / 5 : freq;
clk_disable_unprepare(xcvr->phy_clk);
ret = clk_set_rate(xcvr->phy_clk, freq);
if (ret < 0) {
@ -409,11 +409,21 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
u32 m_ctl = 0, v_ctl = 0;
u32 r = substream->runtime->rate, ch = substream->runtime->channels;
u32 fout = 32 * r * ch * 10 * 2;
u32 fout = 32 * r * ch * 10;
int ret = 0;
switch (xcvr->mode) {
case FSL_XCVR_MODE_SPDIF:
if (xcvr->soc_data->spdif_only && tx) {
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL_SET,
FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM,
FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM);
if (ret < 0) {
dev_err(dai->dev, "Failed to set bypass fem: %d\n", ret);
return ret;
}
}
fallthrough;
case FSL_XCVR_MODE_ARC:
if (tx) {
ret = fsl_xcvr_en_aud_pll(xcvr, fout);

View File

@ -83,6 +83,7 @@ enum {
#define BYT_RT5640_HSMIC2_ON_IN1 BIT(27)
#define BYT_RT5640_JD_HP_ELITEP_1000G2 BIT(28)
#define BYT_RT5640_USE_AMCR0F28 BIT(29)
#define BYT_RT5640_SWAPPED_SPEAKERS BIT(30)
#define BYTCR_INPUT_DEFAULTS \
(BYT_RT5640_IN3_MAP | \
@ -157,6 +158,8 @@ static void log_quirks(struct device *dev)
dev_info(dev, "quirk MONO_SPEAKER enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS)
dev_info(dev, "quirk NO_SPEAKERS enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_SWAPPED_SPEAKERS)
dev_info(dev, "quirk SWAPPED_SPEAKERS enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT)
dev_info(dev, "quirk LINEOUT enabled\n");
if (byt_rt5640_quirk & BYT_RT5640_LINEOUT_AS_HP2)
@ -894,6 +897,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{
/* Medion Lifetab S10346 */
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"),
/* Above strings are much too generic, also match on BIOS date */
DMI_MATCH(DMI_BIOS_DATE, "10/22/2015"),
},
.driver_data = (void *)(BYTCR_INPUT_DEFAULTS |
BYT_RT5640_SWAPPED_SPEAKERS |
BYT_RT5640_SSP0_AIF1 |
BYT_RT5640_MCLK_EN),
},
{ /* Mele PCG03 Mini PC */
.matches = {
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Mini PC"),
@ -1619,11 +1635,11 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
const char *platform_name;
struct acpi_device *adev;
struct device *codec_dev;
const char *cfg_spk;
bool sof_parent;
int ret_val = 0;
int dai_index = 0;
int i, cfg_spk;
int aif;
int i, aif;
is_bytcr = false;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@ -1783,13 +1799,16 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
}
if (byt_rt5640_quirk & BYT_RT5640_NO_SPEAKERS) {
cfg_spk = 0;
cfg_spk = "0";
spk_type = "none";
} else if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) {
cfg_spk = 1;
cfg_spk = "1";
spk_type = "mono";
} else if (byt_rt5640_quirk & BYT_RT5640_SWAPPED_SPEAKERS) {
cfg_spk = "swapped";
spk_type = "swapped";
} else {
cfg_spk = 2;
cfg_spk = "2";
spk_type = "stereo";
}
@ -1804,7 +1823,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
headset2_string = " cfg-hs2:in1";
snprintf(byt_rt5640_components, sizeof(byt_rt5640_components),
"cfg-spk:%d cfg-mic:%s aif:%d%s%s", cfg_spk,
"cfg-spk:%s cfg-mic:%s aif:%d%s%s", cfg_spk,
map_name[BYT_RT5640_MAP(byt_rt5640_quirk)], aif,
lineout_string, headset2_string);
byt_rt5640_card.components = byt_rt5640_components;

View File

@ -154,6 +154,8 @@ static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params)
card->dapm_widgets = skl_hda_widgets;
card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets);
if (!ctx->idisp_codec) {
card->dapm_routes = &skl_hda_map[IDISP_ROUTE_COUNT];
num_route -= IDISP_ROUTE_COUNT;
for (i = 0; i < IDISP_DAI_COUNT; i++) {
skl_hda_be_dai_links[i].codecs = &snd_soc_dummy_dlc;
skl_hda_be_dai_links[i].num_codecs = 1;

View File

@ -1546,7 +1546,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
{
struct device *dev = card->dev;
struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, hdmi_num = 0, bt_num = 0;
int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0;
struct mc_private *ctx = snd_soc_card_get_drvdata(card);
struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params;
const struct snd_soc_acpi_link_adr *adr_link = mach_params->links;
@ -1564,6 +1564,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
char *codec_name, *codec_dai_name;
int i, j, be_id = 0;
int codec_index;
int hdmi_num;
int ret;
ret = get_dailink_info(dev, adr_link, &sdw_be_num, &codec_conf_num);
@ -1584,14 +1585,13 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
ssp_num = hweight_long(ssp_mask);
}
if (mach_params->codec_mask & IDISP_CODEC_MASK) {
if (mach_params->codec_mask & IDISP_CODEC_MASK)
ctx->hdmi.idisp_codec = true;
if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
hdmi_num = SOF_TGL_HDMI_COUNT;
else
hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
}
if (sof_sdw_quirk & SOF_SDW_TGL_HDMI)
hdmi_num = SOF_TGL_HDMI_COUNT;
else
hdmi_num = SOF_PRE_TGL_HDMI_COUNT;
/* enable dmic01 & dmic16k */
if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num)
@ -1601,7 +1601,8 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
bt_num = 1;
dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n",
sdw_be_num, ssp_num, dmic_num, hdmi_num, bt_num);
sdw_be_num, ssp_num, dmic_num,
ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num);
/* allocate BE dailinks */
num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num;

View File

@ -306,13 +306,13 @@ static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = {
.adr = 0x00013701FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_r_endpoint,
.name_prefix = "cs35l56-8"
.name_prefix = "AMP8"
},
{
.adr = 0x00013601FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_3_endpoint,
.name_prefix = "cs35l56-7"
.name_prefix = "AMP7"
}
};
@ -321,13 +321,13 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_adr[] = {
.adr = 0x00023301FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_l_endpoint,
.name_prefix = "cs35l56-1"
.name_prefix = "AMP1"
},
{
.adr = 0x00023201FA355601ull,
.num_endpoints = 1,
.endpoints = &spk_2_endpoint,
.name_prefix = "cs35l56-2"
.name_prefix = "AMP2"
}
};

View File

@ -245,8 +245,10 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
snd_pcm_set_sync(substream);
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
if (!mconfig)
if (!mconfig) {
kfree(dma_params);
return -EINVAL;
}
skl_tplg_d0i3_get(skl, mconfig->d0i3_caps);
@ -1467,6 +1469,7 @@ int skl_platform_register(struct device *dev)
dais = krealloc(skl->dais, sizeof(skl_fe_dai) +
sizeof(skl_platform_dai), GFP_KERNEL);
if (!dais) {
kfree(skl->dais);
ret = -ENOMEM;
goto err;
}
@ -1479,8 +1482,10 @@ int skl_platform_register(struct device *dev)
ret = devm_snd_soc_register_component(dev, &skl_component,
skl->dais, num_dais);
if (ret)
if (ret) {
kfree(skl->dais);
dev_err(dev, "soc component registration failed %d\n", ret);
}
err:
return ret;
}

View File

@ -1003,8 +1003,10 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc,
reply.size = (reply.header >> 32) & IPC_DATA_OFFSET_SZ_MASK;
buf = krealloc(reply.data, reply.size, GFP_KERNEL);
if (!buf)
if (!buf) {
kfree(reply.data);
return -ENOMEM;
}
*payload = buf;
*bytes = reply.size;

View File

@ -27,6 +27,23 @@ struct sc8280xp_snd_data {
static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
{
struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct snd_soc_card *card = rtd->card;
switch (cpu_dai->id) {
case WSA_CODEC_DMA_RX_0:
case WSA_CODEC_DMA_RX_1:
/*
* set limit of 0dB on Digital Volume for Speakers,
* this can prevent damage of speakers to some extent without
* active speaker protection
*/
snd_soc_limit_volume(card, "WSA_RX0 Digital Volume", 84);
snd_soc_limit_volume(card, "WSA_RX1 Digital Volume", 84);
break;
default:
break;
}
return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
}

View File

@ -661,7 +661,7 @@ int snd_soc_limit_volume(struct snd_soc_card *card,
kctl = snd_soc_card_get_kcontrol(card, name);
if (kctl) {
struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value;
if (max <= mc->max) {
if (max <= mc->max - mc->min) {
mc->platform_max = max;
ret = 0;
}

View File

@ -712,11 +712,6 @@ static int soc_pcm_clean(struct snd_soc_pcm_runtime *rtd,
if (snd_soc_dai_active(dai) == 0 &&
(dai->rate || dai->channels || dai->sample_bits))
soc_pcm_set_dai_params(dai, NULL);
if (snd_soc_dai_stream_active(dai, substream->stream) == 0) {
if (dai->driver->ops && !dai->driver->ops->mute_unmute_on_trigger)
snd_soc_dai_digital_mute(dai, 1, substream->stream);
}
}
}
@ -955,8 +950,10 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd,
if (snd_soc_dai_active(dai) == 1)
soc_pcm_set_dai_params(dai, NULL);
if (snd_soc_dai_stream_active(dai, substream->stream) == 1)
snd_soc_dai_digital_mute(dai, 1, substream->stream);
if (snd_soc_dai_stream_active(dai, substream->stream) == 1) {
if (dai->driver->ops && !dai->driver->ops->mute_unmute_on_trigger)
snd_soc_dai_digital_mute(dai, 1, substream->stream);
}
}
/* run the stream event */

View File

@ -493,6 +493,7 @@ static int sof_ipc3_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_pipeline *spipe = swidget->spipe;
struct sof_ipc_pipe_new *pipeline;
struct snd_sof_widget *comp_swidget;
int ret;
@ -545,6 +546,7 @@ static int sof_ipc3_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
swidget->dynamic_pipeline_widget);
swidget->core = pipeline->core;
spipe->core_mask |= BIT(pipeline->core);
return 0;

View File

@ -89,7 +89,7 @@ sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidge
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
struct sof_ipc4_gain *gain = swidget->private;
struct sof_ipc4_msg *msg = &cdata->msg;
struct sof_ipc4_gain_data data;
struct sof_ipc4_gain_params params;
bool all_channels_equal = true;
u32 value;
int ret, i;
@ -109,20 +109,20 @@ sof_ipc4_set_volume_data(struct snd_sof_dev *sdev, struct snd_sof_widget *swidge
*/
for (i = 0; i < scontrol->num_channels; i++) {
if (all_channels_equal) {
data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
data.init_val = cdata->chanv[0].value;
params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
params.init_val = cdata->chanv[0].value;
} else {
data.channels = cdata->chanv[i].channel;
data.init_val = cdata->chanv[i].value;
params.channels = cdata->chanv[i].channel;
params.init_val = cdata->chanv[i].value;
}
/* set curve type and duration from topology */
data.curve_duration_l = gain->data.curve_duration_l;
data.curve_duration_h = gain->data.curve_duration_h;
data.curve_type = gain->data.curve_type;
params.curve_duration_l = gain->data.params.curve_duration_l;
params.curve_duration_h = gain->data.params.curve_duration_h;
params.curve_type = gain->data.params.curve_type;
msg->data_ptr = &data;
msg->data_size = sizeof(data);
msg->data_ptr = &params;
msg->data_size = sizeof(params);
ret = sof_ipc4_set_get_kcontrol_data(scontrol, true, lock);
msg->data_ptr = NULL;

View File

@ -130,18 +130,18 @@ static const struct sof_topology_token comp_ext_tokens[] = {
static const struct sof_topology_token gain_tokens[] = {
{SOF_TKN_GAIN_RAMP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_u32, offsetof(struct sof_ipc4_gain_data, curve_type)},
get_token_u32, offsetof(struct sof_ipc4_gain_params, curve_type)},
{SOF_TKN_GAIN_RAMP_DURATION,
SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_gain_data, curve_duration_l)},
offsetof(struct sof_ipc4_gain_params, curve_duration_l)},
{SOF_TKN_GAIN_VAL, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)},
get_token_u32, offsetof(struct sof_ipc4_gain_params, init_val)},
};
/* SRC */
static const struct sof_topology_token src_tokens[] = {
{SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc4_src, sink_rate)},
offsetof(struct sof_ipc4_src_data, sink_rate)},
};
static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
@ -656,6 +656,7 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
struct sof_ipc4_pipeline *pipeline;
struct snd_sof_pipeline *spipe = swidget->spipe;
int ret;
pipeline = kzalloc(sizeof(*pipeline), GFP_KERNEL);
@ -670,6 +671,7 @@ static int sof_ipc4_widget_setup_comp_pipeline(struct snd_sof_widget *swidget)
}
swidget->core = pipeline->core_id;
spipe->core_mask |= BIT(pipeline->core_id);
if (pipeline->use_chain_dma) {
dev_dbg(scomp->dev, "Set up chain DMA for %s\n", swidget->widget->name);
@ -718,15 +720,15 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
swidget->private = gain;
gain->data.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
gain->data.init_val = SOF_IPC4_VOL_ZERO_DB;
gain->data.params.channels = SOF_IPC4_GAIN_ALL_CHANNELS_MASK;
gain->data.params.init_val = SOF_IPC4_VOL_ZERO_DB;
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->base_config);
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &gain->available_fmt, &gain->data.base_config);
if (ret)
goto err;
ret = sof_update_ipc_object(scomp, &gain->data, SOF_GAIN_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(gain->data), 1);
ret = sof_update_ipc_object(scomp, &gain->data.params, SOF_GAIN_TOKENS,
swidget->tuples, swidget->num_tuples, sizeof(gain->data), 1);
if (ret) {
dev_err(scomp->dev, "Parsing gain tokens failed\n");
goto err;
@ -734,8 +736,8 @@ static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget)
dev_dbg(scomp->dev,
"pga widget %s: ramp type: %d, ramp duration %d, initial gain value: %#x\n",
swidget->widget->name, gain->data.curve_type, gain->data.curve_duration_l,
gain->data.init_val);
swidget->widget->name, gain->data.params.curve_type,
gain->data.params.curve_duration_l, gain->data.params.init_val);
ret = sof_ipc4_widget_setup_msg(swidget, &gain->msg);
if (ret)
@ -797,6 +799,7 @@ err:
static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
struct snd_sof_pipeline *spipe = swidget->spipe;
struct sof_ipc4_src *src;
int ret;
@ -808,18 +811,21 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget)
swidget->private = src;
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, &src->base_config);
ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt,
&src->data.base_config);
if (ret)
goto err;
ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples,
ret = sof_update_ipc_object(scomp, &src->data, SOF_SRC_TOKENS, swidget->tuples,
swidget->num_tuples, sizeof(*src), 1);
if (ret) {
dev_err(scomp->dev, "Parsing SRC tokens failed\n");
goto err;
}
dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
spipe->core_mask |= BIT(swidget->core);
dev_dbg(scomp->dev, "SRC sink rate %d\n", src->data.sink_rate);
ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
if (ret)
@ -864,6 +870,7 @@ static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
{
struct snd_soc_component *scomp = swidget->scomp;
struct sof_ipc4_fw_module *fw_module;
struct snd_sof_pipeline *spipe = swidget->spipe;
struct sof_ipc4_process *process;
void *cfg;
int ret;
@ -920,6 +927,9 @@ static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget)
sof_ipc4_widget_update_kcontrol_module_id(swidget);
/* set pipeline core mask to keep track of the core the module is scheduled to run on */
spipe->core_mask |= BIT(swidget->core);
return 0;
free_base_cfg_ext:
kfree(process->base_config_ext);
@ -1816,7 +1826,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
int ret;
ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->base_config,
ret = sof_ipc4_init_input_audio_fmt(sdev, swidget, &gain->data.base_config,
pipeline_params, available_fmt);
if (ret < 0)
return ret;
@ -1826,7 +1836,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
out_ref_channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(in_fmt->fmt_cfg);
out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_fmt->fmt_cfg);
ret = sof_ipc4_init_output_audio_fmt(sdev, &gain->base_config, available_fmt,
ret = sof_ipc4_init_output_audio_fmt(sdev, &gain->data.base_config, available_fmt,
out_ref_rate, out_ref_channels, out_ref_valid_bits);
if (ret < 0) {
dev_err(sdev->dev, "Failed to initialize output format for %s",
@ -1835,7 +1845,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
}
/* update pipeline memory usage */
sof_ipc4_update_resource_usage(sdev, swidget, &gain->base_config);
sof_ipc4_update_resource_usage(sdev, swidget, &gain->data.base_config);
return 0;
}
@ -1891,7 +1901,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
u32 out_ref_rate, out_ref_channels, out_ref_valid_bits;
int output_format_index, input_format_index;
input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->base_config,
input_format_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &src->data.base_config,
pipeline_params, available_fmt);
if (input_format_index < 0)
return input_format_index;
@ -1921,7 +1931,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
*/
out_ref_rate = params_rate(fe_params);
output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->base_config,
output_format_index = sof_ipc4_init_output_audio_fmt(sdev, &src->data.base_config,
available_fmt, out_ref_rate,
out_ref_channels, out_ref_valid_bits);
if (output_format_index < 0) {
@ -1931,10 +1941,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget,
}
/* update pipeline memory usage */
sof_ipc4_update_resource_usage(sdev, swidget, &src->base_config);
sof_ipc4_update_resource_usage(sdev, swidget, &src->data.base_config);
out_audio_fmt = &available_fmt->output_pin_fmts[output_format_index].audio_fmt;
src->sink_rate = out_audio_fmt->sampling_frequency;
src->data.sink_rate = out_audio_fmt->sampling_frequency;
/* update pipeline_params for sink widgets */
return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt);
@ -2314,9 +2324,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
{
struct sof_ipc4_gain *gain = swidget->private;
ipc_size = sizeof(struct sof_ipc4_base_module_cfg) +
sizeof(struct sof_ipc4_gain_data);
ipc_data = gain;
ipc_size = sizeof(gain->data);
ipc_data = &gain->data;
msg = &gain->msg;
break;
@ -2335,8 +2344,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
{
struct sof_ipc4_src *src = swidget->private;
ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate);
ipc_data = src;
ipc_size = sizeof(src->data);
ipc_data = &src->data;
msg = &src->msg;
break;

View File

@ -361,7 +361,7 @@ struct sof_ipc4_control_msg_payload {
} __packed;
/**
* struct sof_ipc4_gain_data - IPC gain blob
* struct sof_ipc4_gain_params - IPC gain parameters
* @channels: Channels
* @init_val: Initial value
* @curve_type: Curve type
@ -369,24 +369,32 @@ struct sof_ipc4_control_msg_payload {
* @curve_duration_l: Curve duration low part
* @curve_duration_h: Curve duration high part
*/
struct sof_ipc4_gain_data {
struct sof_ipc4_gain_params {
uint32_t channels;
uint32_t init_val;
uint32_t curve_type;
uint32_t reserved;
uint32_t curve_duration_l;
uint32_t curve_duration_h;
} __aligned(8);
} __packed __aligned(4);
/**
* struct sof_ipc4_gain_data - IPC gain init blob
* @base_config: IPC base config data
* @params: Initial parameters for the gain module
*/
struct sof_ipc4_gain_data {
struct sof_ipc4_base_module_cfg base_config;
struct sof_ipc4_gain_params params;
} __packed __aligned(4);
/**
* struct sof_ipc4_gain - gain config data
* @base_config: IPC base config data
* @data: IPC gain blob
* @available_fmt: Available audio format
* @msg: message structure for gain
*/
struct sof_ipc4_gain {
struct sof_ipc4_base_module_cfg base_config;
struct sof_ipc4_gain_data data;
struct sof_ipc4_available_audio_format available_fmt;
struct sof_ipc4_msg msg;
@ -404,16 +412,24 @@ struct sof_ipc4_mixer {
struct sof_ipc4_msg msg;
};
/**
* struct sof_ipc4_src SRC config data
/*
* struct sof_ipc4_src_data - IPC data for SRC
* @base_config: IPC base config data
* @sink_rate: Output rate for sink module
*/
struct sof_ipc4_src_data {
struct sof_ipc4_base_module_cfg base_config;
uint32_t sink_rate;
} __packed __aligned(4);
/**
* struct sof_ipc4_src - SRC config data
* @data: IPC base config data
* @available_fmt: Available audio format
* @msg: IPC4 message struct containing header and data info
*/
struct sof_ipc4_src {
struct sof_ipc4_base_module_cfg base_config;
uint32_t sink_rate;
struct sof_ipc4_src_data data;
struct sof_ipc4_available_audio_format available_fmt;
struct sof_ipc4_msg msg;
};

View File

@ -46,6 +46,7 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget)
{
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_pipeline *spipe = swidget->spipe;
struct snd_sof_widget *pipe_widget;
int err = 0;
int ret;
@ -87,15 +88,22 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
}
/*
* disable widget core. continue to route setup status and complete flag
* even if this fails and return the appropriate error
* decrement ref count for cores associated with all modules in the pipeline and clear
* the complete flag
*/
ret = snd_sof_dsp_core_put(sdev, swidget->core);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to disable target core: %d for widget %s\n",
swidget->core, swidget->widget->name);
if (!err)
err = ret;
if (swidget->id == snd_soc_dapm_scheduler) {
int i;
for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
ret = snd_sof_dsp_core_put(sdev, i);
if (ret < 0) {
dev_err(sdev->dev, "failed to disable target core: %d for pipeline %s\n",
i, swidget->widget->name);
if (!err)
err = ret;
}
}
swidget->spipe->complete = 0;
}
/*
@ -108,10 +116,6 @@ static int sof_widget_free_unlocked(struct snd_sof_dev *sdev,
err = ret;
}
/* clear pipeline complete */
if (swidget->id == snd_soc_dapm_scheduler)
swidget->spipe->complete = 0;
if (!err)
dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);
@ -134,8 +138,10 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget)
{
const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
struct snd_sof_pipeline *spipe = swidget->spipe;
bool use_count_decremented = false;
int ret;
int i;
/* skip if there is no private data */
if (!swidget->private)
@ -166,19 +172,23 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
goto use_count_dec;
}
/* enable widget core */
ret = snd_sof_dsp_core_get(sdev, swidget->core);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to enable target core for widget %s\n",
swidget->widget->name);
goto pipe_widget_free;
/* update ref count for cores associated with all modules in the pipeline */
if (swidget->id == snd_soc_dapm_scheduler) {
for_each_set_bit(i, &spipe->core_mask, sdev->num_cores) {
ret = snd_sof_dsp_core_get(sdev, i);
if (ret < 0) {
dev_err(sdev->dev, "failed to enable target core %d for pipeline %s\n",
i, swidget->widget->name);
goto pipe_widget_free;
}
}
}
/* setup widget in the DSP */
if (tplg_ops && tplg_ops->widget_setup) {
ret = tplg_ops->widget_setup(sdev, swidget);
if (ret < 0)
goto core_put;
goto pipe_widget_free;
}
/* send config for DAI components */
@ -208,15 +218,22 @@ static int sof_widget_setup_unlocked(struct snd_sof_dev *sdev,
return 0;
widget_free:
/* widget use_count and core ref_count will both be decremented by sof_widget_free() */
/* widget use_count will be decremented by sof_widget_free() */
sof_widget_free_unlocked(sdev, swidget);
use_count_decremented = true;
core_put:
if (!use_count_decremented)
snd_sof_dsp_core_put(sdev, swidget->core);
pipe_widget_free:
if (swidget->id != snd_soc_dapm_scheduler)
if (swidget->id != snd_soc_dapm_scheduler) {
sof_widget_free_unlocked(sdev, swidget->spipe->pipe_widget);
} else {
int j;
/* decrement ref count for all cores that were updated previously */
for_each_set_bit(j, &spipe->core_mask, sdev->num_cores) {
if (j >= i)
break;
snd_sof_dsp_core_put(sdev, j);
}
}
use_count_dec:
if (!use_count_decremented)
swidget->use_count--;

View File

@ -480,6 +480,7 @@ struct snd_sof_widget {
* @paused_count: Count of number of PCM's that have started and have currently paused this
pipeline
* @complete: flag used to indicate that pipeline set up is complete.
* @core_mask: Mask containing target cores for all modules in the pipeline
* @list: List item in sdev pipeline_list
*/
struct snd_sof_pipeline {
@ -487,6 +488,7 @@ struct snd_sof_pipeline {
int started_count;
int paused_count;
int complete;
unsigned long core_mask;
struct list_head list;
};

View File

@ -1736,8 +1736,10 @@ static int sof_dai_load(struct snd_soc_component *scomp, int index,
/* perform pcm set op */
if (ipc_pcm_ops && ipc_pcm_ops->pcm_setup) {
ret = ipc_pcm_ops->pcm_setup(sdev, spcm);
if (ret < 0)
if (ret < 0) {
kfree(spcm);
return ret;
}
}
dai_drv->dobj.private = spcm;

View File

@ -2978,6 +2978,7 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
#define SND_DJM_850_IDX 0x2
#define SND_DJM_900NXS2_IDX 0x3
#define SND_DJM_750MK2_IDX 0x4
#define SND_DJM_450_IDX 0x5
#define SND_DJM_CTL(_name, suffix, _default_value, _windex) { \
@ -3108,6 +3109,31 @@ static const struct snd_djm_ctl snd_djm_ctls_250mk2[] = {
};
// DJM-450
static const u16 snd_djm_opts_450_cap1[] = {
0x0103, 0x0100, 0x0106, 0x0107, 0x0108, 0x0109, 0x010d, 0x010a };
static const u16 snd_djm_opts_450_cap2[] = {
0x0203, 0x0200, 0x0206, 0x0207, 0x0208, 0x0209, 0x020d, 0x020a };
static const u16 snd_djm_opts_450_cap3[] = {
0x030a, 0x0311, 0x0312, 0x0307, 0x0308, 0x0309, 0x030d };
static const u16 snd_djm_opts_450_pb1[] = { 0x0100, 0x0101, 0x0104 };
static const u16 snd_djm_opts_450_pb2[] = { 0x0200, 0x0201, 0x0204 };
static const u16 snd_djm_opts_450_pb3[] = { 0x0300, 0x0301, 0x0304 };
static const struct snd_djm_ctl snd_djm_ctls_450[] = {
SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL),
SND_DJM_CTL("Ch1 Input", 450_cap1, 2, SND_DJM_WINDEX_CAP),
SND_DJM_CTL("Ch2 Input", 450_cap2, 2, SND_DJM_WINDEX_CAP),
SND_DJM_CTL("Ch3 Input", 450_cap3, 0, SND_DJM_WINDEX_CAP),
SND_DJM_CTL("Ch1 Output", 450_pb1, 0, SND_DJM_WINDEX_PB),
SND_DJM_CTL("Ch2 Output", 450_pb2, 1, SND_DJM_WINDEX_PB),
SND_DJM_CTL("Ch3 Output", 450_pb3, 2, SND_DJM_WINDEX_PB)
};
// DJM-750
static const u16 snd_djm_opts_750_cap1[] = {
0x0101, 0x0103, 0x0106, 0x0107, 0x0108, 0x0109, 0x010a, 0x010f };
@ -3203,6 +3229,7 @@ static const struct snd_djm_device snd_djm_devices[] = {
[SND_DJM_850_IDX] = SND_DJM_DEVICE(850),
[SND_DJM_900NXS2_IDX] = SND_DJM_DEVICE(900nxs2),
[SND_DJM_750MK2_IDX] = SND_DJM_DEVICE(750mk2),
[SND_DJM_450_IDX] = SND_DJM_DEVICE(450),
};
@ -3454,6 +3481,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX);
break;
case USB_ID(0x2b73, 0x0013): /* Pioneer DJ DJM-450 */
err = snd_djm_controls_create(mixer, SND_DJM_450_IDX);
break;
case USB_ID(0x08e4, 0x017f): /* Pioneer DJ DJM-750 */
err = snd_djm_controls_create(mixer, SND_DJM_750_IDX);
break;

View File

@ -1387,7 +1387,7 @@ free_buf:
static int snd_usb_motu_m_series_boot_quirk(struct usb_device *dev)
{
msleep(2000);
msleep(4000);
return 0;
}
@ -1630,7 +1630,7 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev,
unsigned int id)
{
switch (id) {
case USB_ID(0x07fd, 0x0008): /* MOTU M Series */
case USB_ID(0x07fd, 0x0008): /* MOTU M Series, 1st hardware version */
return snd_usb_motu_m_series_boot_quirk(dev);
}

View File

@ -138,7 +138,7 @@ static void find_controls(void)
err = snd_ctl_elem_info(card_data->handle,
ctl_data->info);
if (err < 0) {
ksft_print_msg("%s getting info for %d\n",
ksft_print_msg("%s getting info for %s\n",
snd_strerror(err),
ctl_data->name);
}