Commit 3abf66a4 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/cs35l41' into for-next



Pull CS35L41 codec extension series.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parents 126c18a4 42320660
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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[] = {
+12 −1
Original line number Diff line number Diff line
@@ -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,
};
+29 −4
Original line number Diff line number Diff line
@@ -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);
	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;
		}
+24 −3
Original line number Diff line number Diff line
@@ -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 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
	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 @@ int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int i
	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);
+14 −3
Original line number Diff line number Diff line
@@ -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);

Loading