Unverified Commit 2e411e93 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: cs35l56: Fixes to handling of ASP1 config

Merge series from Richard Fitzgerald <rf@opensource.cirrus.com>:

This chain fixes some problems with some previous patches for handling
the ASP1 config registers. The root of the problem is that the ownership
of these registers can be either with the firmware or the driver, and that
the chip has to be soft-reset after downloading the firmware.

This chain adds and uses a regmap_read_bypassed() function so that the
driver can leave the regmap in cache-only until the chip has rebooted,
but still poll a register to detect when the chip has rebooted.

Richard Fitzgerald (4):
  regmap: Add regmap_read_bypassed()
  ALSA: hda: cs35l56: Exit cache-only after
    cs35l56_wait_for_firmware_boot()
  ASoC: cs35l56: Fix unintended bus access while resetting amp
  ASoC: cs35l56: Prevent overwriting firmware ASP config

 drivers/base/regmap/regmap.c      | 37 ++++++++++++++
 include/linux/regmap.h            |  8 +++
 include/sound/cs35l56.h           |  2 +
 sound/pci/hda/cs35l56_hda.c       |  4 ++
 sound/soc/codecs/cs35l56-sdw.c    |  2 -
 sound/soc/codecs/cs35l56-shared.c | 83 ++++++++++++++++++++-----------
 sound/soc/codecs/cs35l56.c        | 26 +++++++++-
 7 files changed, 130 insertions(+), 32 deletions(-)

--
2.39.2
parents f23e8f3a dfd2ffb3
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -2838,6 +2838,43 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
}
EXPORT_SYMBOL_GPL(regmap_read);

/**
 * regmap_read_bypassed() - Read a value from a single register direct
 *			    from the device, bypassing the cache
 *
 * @map: Register map to read from
 * @reg: Register to be read from
 * @val: Pointer to store read value
 *
 * A value of zero will be returned on success, a negative errno will
 * be returned in error cases.
 */
int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val)
{
	int ret;
	bool bypass, cache_only;

	if (!IS_ALIGNED(reg, map->reg_stride))
		return -EINVAL;

	map->lock(map->lock_arg);

	bypass = map->cache_bypass;
	cache_only = map->cache_only;
	map->cache_bypass = true;
	map->cache_only = false;

	ret = _regmap_read(map, reg, val);

	map->cache_bypass = bypass;
	map->cache_only = cache_only;

	map->unlock(map->lock_arg);

	return ret;
}
EXPORT_SYMBOL_GPL(regmap_read_bypassed);

/**
 * regmap_raw_read() - Read raw data from the device
 *
+8 −0
Original line number Diff line number Diff line
@@ -1230,6 +1230,7 @@ int regmap_multi_reg_write_bypassed(struct regmap *map,
int regmap_raw_write_async(struct regmap *map, unsigned int reg,
			   const void *val, size_t val_len);
int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val);
int regmap_read_bypassed(struct regmap *map, unsigned int reg, unsigned int *val);
int regmap_raw_read(struct regmap *map, unsigned int reg,
		    void *val, size_t val_len);
int regmap_noinc_read(struct regmap *map, unsigned int reg,
@@ -1739,6 +1740,13 @@ static inline int regmap_read(struct regmap *map, unsigned int reg,
	return -EINVAL;
}

static inline int regmap_read_bypassed(struct regmap *map, unsigned int reg,
				       unsigned int *val)
{
	WARN_ONCE(1, "regmap API is disabled");
	return -EINVAL;
}

static inline int regmap_raw_read(struct regmap *map, unsigned int reg,
				  void *val, size_t val_len)
{
+2 −0
Original line number Diff line number Diff line
@@ -267,6 +267,7 @@ struct cs35l56_base {
	bool fw_patched;
	bool secured;
	bool can_hibernate;
	bool fw_owns_asp1;
	bool cal_data_valid;
	s8 cal_index;
	struct cirrus_amp_cal_data cal_data;
@@ -283,6 +284,7 @@ extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];

int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
int cs35l56_init_asp1_regs_for_driver_control(struct cs35l56_base *cs35l56_base);
int cs35l56_force_sync_asp1_registers_from_cache(struct cs35l56_base *cs35l56_base);
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base);
+4 −0
Original line number Diff line number Diff line
@@ -644,6 +644,8 @@ static int cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
		ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
		if (ret)
			goto err_powered_up;

		regcache_cache_only(cs35l56->base.regmap, false);
	}

	/* Disable auto-hibernate so that runtime_pm has control */
@@ -1002,6 +1004,8 @@ int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
	if (ret)
		goto err;

	regcache_cache_only(cs35l56->base.regmap, false);

	ret = cs35l56_set_patch(&cs35l56->base);
	if (ret)
		goto err;
+0 −2
Original line number Diff line number Diff line
@@ -188,8 +188,6 @@ static void cs35l56_sdw_init(struct sdw_slave *peripheral)
			goto out;
	}

	regcache_cache_only(cs35l56->base.regmap, false);

	ret = cs35l56_init(cs35l56);
	if (ret < 0) {
		regcache_cache_only(cs35l56->base.regmap, true);
Loading