Unverified Commit 1d78e193 authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: Initial support for Cirrus Logic CS35L56

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

The CS35L56 is a high-performance boosted mono audio amplifier.
Supported control interfaces are I2C, SPI or SoundWire.
Supported audio interfaces are I2S/TDM or SoundWire.

The CS35L56 has a self-booting firmware in ROM, with the ability
to patch the firmware and/or apply tunings.
Patches #1 to #7 add support to cs_dsp and wm_adsp for self-booting
firmware and the ability to apply a .bin file without having to
apply a .wmfw.
parents 4af574f5 e4961125
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -4905,6 +4905,7 @@ L: patches@opensource.cirrus.com
S:	Maintained
F:	Documentation/devicetree/bindings/sound/cirrus,cs*
F:	include/dt-bindings/sound/cs*
F:	include/sound/cs*
F:	sound/pci/hda/cs*
F:	sound/pci/hda/hda_cs_dsp_ctl.*
F:	sound/soc/codecs/cs*
+16 −1
Original line number Diff line number Diff line
@@ -301,6 +301,7 @@ struct cs_dsp_ops {
static const struct cs_dsp_ops cs_dsp_adsp1_ops;
static const struct cs_dsp_ops cs_dsp_adsp2_ops[];
static const struct cs_dsp_ops cs_dsp_halo_ops;
static const struct cs_dsp_ops cs_dsp_halo_ao_ops;

struct cs_dsp_buf {
	struct list_head list;
@@ -1300,6 +1301,9 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
	int regions = 0;
	int ret, offset, type;

	if (!firmware)
		return 0;

	ret = -EINVAL;

	pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer);
@@ -2821,6 +2825,9 @@ EXPORT_SYMBOL_NS_GPL(cs_dsp_adsp2_init, FW_CS_DSP);
 */
int cs_dsp_halo_init(struct cs_dsp *dsp)
{
	if (dsp->no_core_startstop)
		dsp->ops = &cs_dsp_halo_ao_ops;
	else
		dsp->ops = &cs_dsp_halo_ops;

	return cs_dsp_common_init(dsp);
@@ -3187,6 +3194,14 @@ static const struct cs_dsp_ops cs_dsp_halo_ops = {
	.stop_core = cs_dsp_halo_stop_core,
};

static const struct cs_dsp_ops cs_dsp_halo_ao_ops = {
	.parse_sizes = cs_dsp_adsp2_parse_sizes,
	.validate_version = cs_dsp_halo_validate_version,
	.setup_algs = cs_dsp_halo_setup_algs,
	.region_to_reg = cs_dsp_halo_region_to_reg,
	.show_fw_status = cs_dsp_halo_show_fw_status,
};

/**
 * cs_dsp_chunk_write() - Format data to a DSP memory chunk
 * @ch: Pointer to the chunk structure
+1 −0
Original line number Diff line number Diff line
@@ -156,6 +156,7 @@ struct cs_dsp {
	unsigned int sysclk_reg;
	unsigned int sysclk_mask;
	unsigned int sysclk_shift;
	bool no_core_startstop;

	struct list_head alg_regions;

+266 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Common definitions for Cirrus Logic CS35L56 smart amp
 *
 * Copyright (C) 2023 Cirrus Logic, Inc. and
 *                    Cirrus Logic International Semiconductor Ltd.
 */

#ifndef __CS35L56_H
#define __CS35L56_H

#include <linux/firmware/cirrus/cs_dsp.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>

#define CS35L56_DEVID					0x0000000
#define CS35L56_REVID					0x0000004
#define CS35L56_RELID					0x000000C
#define CS35L56_OTPID					0x0000010
#define CS35L56_SFT_RESET				0x0000020
#define CS35L56_GLOBAL_ENABLES				0x0002014
#define CS35L56_BLOCK_ENABLES				0x0002018
#define CS35L56_BLOCK_ENABLES2				0x000201C
#define CS35L56_REFCLK_INPUT				0x0002C04
#define CS35L56_GLOBAL_SAMPLE_RATE			0x0002C0C
#define CS35L56_ASP1_ENABLES1				0x0004800
#define CS35L56_ASP1_CONTROL1				0x0004804
#define CS35L56_ASP1_CONTROL2				0x0004808
#define CS35L56_ASP1_CONTROL3				0x000480C
#define CS35L56_ASP1_FRAME_CONTROL1			0x0004810
#define CS35L56_ASP1_FRAME_CONTROL5			0x0004820
#define CS35L56_ASP1_DATA_CONTROL1			0x0004830
#define CS35L56_ASP1_DATA_CONTROL5			0x0004840
#define CS35L56_DACPCM1_INPUT				0x0004C00
#define CS35L56_DACPCM2_INPUT				0x0004C08
#define CS35L56_ASP1TX1_INPUT				0x0004C20
#define CS35L56_ASP1TX2_INPUT				0x0004C24
#define CS35L56_ASP1TX3_INPUT				0x0004C28
#define CS35L56_ASP1TX4_INPUT				0x0004C2C
#define CS35L56_DSP1RX1_INPUT				0x0004C40
#define CS35L56_DSP1RX2_INPUT				0x0004C44
#define CS35L56_SWIRE_DP3_CH1_INPUT			0x0004C70
#define CS35L56_SWIRE_DP3_CH2_INPUT			0x0004C74
#define CS35L56_SWIRE_DP3_CH3_INPUT			0x0004C78
#define CS35L56_SWIRE_DP3_CH4_INPUT			0x0004C7C
#define CS35L56_SWIRE_DP3_CH5_INPUT			0x0004C80
#define CS35L56_SWIRE_DP3_CH6_INPUT			0x0004C84
#define CS35L56_IRQ1_CFG				0x000E000
#define CS35L56_IRQ1_STATUS				0x000E004
#define CS35L56_IRQ1_EINT_1				0x000E010
#define CS35L56_IRQ1_EINT_2				0x000E014
#define CS35L56_IRQ1_EINT_4				0x000E01C
#define CS35L56_IRQ1_EINT_8				0x000E02C
#define CS35L56_IRQ1_EINT_18				0x000E054
#define CS35L56_IRQ1_EINT_20				0x000E05C
#define CS35L56_IRQ1_MASK_1				0x000E090
#define CS35L56_IRQ1_MASK_2				0x000E094
#define CS35L56_IRQ1_MASK_4				0x000E09C
#define CS35L56_IRQ1_MASK_8				0x000E0AC
#define CS35L56_IRQ1_MASK_18				0x000E0D4
#define CS35L56_IRQ1_MASK_20				0x000E0DC
#define CS35L56_DSP_VIRTUAL1_MBOX_1			0x0011020
#define CS35L56_DSP_VIRTUAL1_MBOX_2			0x0011024
#define CS35L56_DSP_VIRTUAL1_MBOX_3			0x0011028
#define CS35L56_DSP_VIRTUAL1_MBOX_4			0x001102C
#define CS35L56_DSP_VIRTUAL1_MBOX_5			0x0011030
#define CS35L56_DSP_VIRTUAL1_MBOX_6			0x0011034
#define CS35L56_DSP_VIRTUAL1_MBOX_7			0x0011038
#define CS35L56_DSP_VIRTUAL1_MBOX_8			0x001103C
#define CS35L56_DSP_RESTRICT_STS1			0x00190F0
#define CS35L56_DSP1_XMEM_PACKED_0			0x2000000
#define CS35L56_DSP1_XMEM_PACKED_6143			0x2005FFC
#define CS35L56_DSP1_XMEM_UNPACKED32_0			0x2400000
#define CS35L56_DSP1_XMEM_UNPACKED32_4095		0x2403FFC
#define CS35L56_DSP1_SYS_INFO_ID			0x25E0000
#define CS35L56_DSP1_SYS_INFO_END			0x25E004C
#define CS35L56_DSP1_AHBM_WINDOW_DEBUG_0		0x25E2040
#define CS35L56_DSP1_AHBM_WINDOW_DEBUG_1		0x25E2044
#define CS35L56_DSP1_XMEM_UNPACKED24_0			0x2800000
#define CS35L56_DSP1_HALO_STATE_A1			0x2801E58
#define CS35L56_DSP1_HALO_STATE				0x28021E0
#define CS35L56_DSP1_PM_CUR_STATE_A1			0x2804000
#define CS35L56_DSP1_PM_CUR_STATE			0x2804308
#define CS35L56_DSP1_XMEM_UNPACKED24_8191		0x2807FFC
#define CS35L56_DSP1_CORE_BASE				0x2B80000
#define CS35L56_DSP1_SCRATCH1				0x2B805C0
#define CS35L56_DSP1_SCRATCH2				0x2B805C8
#define CS35L56_DSP1_SCRATCH3				0x2B805D0
#define CS35L56_DSP1_SCRATCH4				0x2B805D8
#define CS35L56_DSP1_YMEM_PACKED_0			0x2C00000
#define CS35L56_DSP1_YMEM_PACKED_4604			0x2C047F0
#define CS35L56_DSP1_YMEM_UNPACKED32_0			0x3000000
#define CS35L56_DSP1_YMEM_UNPACKED32_3070		0x3002FF8
#define CS35L56_DSP1_YMEM_UNPACKED24_0			0x3400000
#define CS35L56_MAIN_RENDER_USER_MUTE			0x3400024
#define CS35L56_MAIN_RENDER_USER_VOLUME			0x340002C
#define CS35L56_MAIN_POSTURE_NUMBER			0x3400094
#define CS35L56_TRANSDUCER_ACTUAL_PS			0x3400150
#define CS35L56_DSP1_YMEM_UNPACKED24_6141		0x3405FF4
#define CS35L56_DSP1_PMEM_0				0x3800000
#define CS35L56_DSP1_PMEM_5114				0x3804FE8

/* DEVID */
#define CS35L56_DEVID_MASK				0x00FFFFFF

/* REVID */
#define CS35L56_AREVID_MASK				0x000000F0
#define CS35L56_MTLREVID_MASK				0x0000000F
#define CS35L56_REVID_B0				0x000000B0

/* ASP_ENABLES1 */
#define CS35L56_ASP_RX2_EN_SHIFT			17
#define CS35L56_ASP_RX1_EN_SHIFT			16
#define CS35L56_ASP_TX4_EN_SHIFT			3
#define CS35L56_ASP_TX3_EN_SHIFT			2
#define CS35L56_ASP_TX2_EN_SHIFT			1
#define CS35L56_ASP_TX1_EN_SHIFT			0

/* ASP_CONTROL1 */
#define CS35L56_ASP_BCLK_FREQ_MASK			0x0000003F
#define CS35L56_ASP_BCLK_FREQ_SHIFT			0

/* ASP_CONTROL2 */
#define CS35L56_ASP_RX_WIDTH_MASK			0xFF000000
#define CS35L56_ASP_RX_WIDTH_SHIFT			24
#define CS35L56_ASP_TX_WIDTH_MASK			0x00FF0000
#define CS35L56_ASP_TX_WIDTH_SHIFT			16
#define CS35L56_ASP_FMT_MASK				0x00000700
#define CS35L56_ASP_FMT_SHIFT				8
#define CS35L56_ASP_BCLK_INV_MASK			0x00000040
#define CS35L56_ASP_FSYNC_INV_MASK			0x00000004

/* ASP_CONTROL3 */
#define CS35L56_ASP1_DOUT_HIZ_CTRL_MASK			0x00000003

/* ASP_DATA_CONTROL1 */
#define CS35L56_ASP_TX_WL_MASK				0x0000003F

/* ASP_DATA_CONTROL5 */
#define CS35L56_ASP_RX_WL_MASK				0x0000003F

/* ASPTXn_INPUT */
#define CS35L56_ASP_TXn_SRC_MASK			0x0000007F

/* SWIRETX[1..7]_SRC SDWTXn INPUT */
#define CS35L56_SWIRETXn_SRC_MASK			0x0000007F

/* IRQ1_STATUS */
#define CS35L56_IRQ1_STS_MASK				0x00000001

/* IRQ1_EINT_1 */
#define CS35L56_AMP_SHORT_ERR_EINT1_MASK		0x80000000

/* IRQ1_EINT_2 */
#define CS35L56_DSP_VIRTUAL2_MBOX_WR_EINT1_MASK		0x00200000

/* IRQ1_EINT_4 */
#define CS35L56_OTP_BOOT_DONE_MASK			0x00000002

/* IRQ1_EINT_8 */
#define CS35L56_TEMP_ERR_EINT1_MASK			0x80000000

/* Mixer input sources */
#define CS35L56_INPUT_SRC_NONE				0x00
#define CS35L56_INPUT_SRC_ASP1RX1			0x08
#define CS35L56_INPUT_SRC_ASP1RX2			0x09
#define CS35L56_INPUT_SRC_VMON				0x18
#define CS35L56_INPUT_SRC_IMON				0x19
#define CS35L56_INPUT_SRC_ERR_VOL			0x20
#define CS35L56_INPUT_SRC_CLASSH			0x21
#define CS35L56_INPUT_SRC_VDDBMON			0x28
#define CS35L56_INPUT_SRC_VBSTMON			0x29
#define CS35L56_INPUT_SRC_DSP1TX1			0x32
#define CS35L56_INPUT_SRC_DSP1TX2			0x33
#define CS35L56_INPUT_SRC_DSP1TX3			0x34
#define CS35L56_INPUT_SRC_DSP1TX4			0x35
#define CS35L56_INPUT_SRC_DSP1TX5			0x36
#define CS35L56_INPUT_SRC_DSP1TX6			0x37
#define CS35L56_INPUT_SRC_DSP1TX7			0x38
#define CS35L56_INPUT_SRC_DSP1TX8			0x39
#define CS35L56_INPUT_SRC_TEMPMON			0x3A
#define CS35L56_INPUT_SRC_INTERPOLATOR			0x40
#define CS35L56_INPUT_SRC_SWIRE_RX1			0x44
#define CS35L56_INPUT_SRC_SWIRE_RX2			0x45
#define CS35L56_INPUT_SRC_SWIRE_RX3			0x46
#define CS35L56_INPUT_MASK				0x7F

#define CS35L56_NUM_INPUT_SRC				22

/* ASP formats */
#define CS35L56_ASP_FMT_DSP_A				0
#define CS35L56_ASP_FMT_I2S				2

/* ASP HiZ modes */
#define CS35L56_ASP_UNUSED_HIZ_OFF_HIZ			3

/* MAIN_RENDER_ACTUAL_PS */
#define CS35L56_PS0					0
#define CS35L56_PS3					3

/* CS35L56_DSP_RESTRICT_STS1 */
#define CS35L56_RESTRICTED_MASK				0x7

/* CS35L56_MAIN_RENDER_USER_MUTE */
#define CS35L56_MAIN_RENDER_USER_MUTE_MASK		1

/* CS35L56_MAIN_RENDER_USER_VOLUME */
#define CS35L56_MAIN_RENDER_USER_VOLUME_MIN		-400
#define CS35L56_MAIN_RENDER_USER_VOLUME_MAX		400
#define CS35L56_MAIN_RENDER_USER_VOLUME_MASK		0x0000FFC0
#define CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT		6
#define CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT		9

/* CS35L56_MAIN_POSTURE_NUMBER */
#define CS35L56_MAIN_POSTURE_MIN			0
#define CS35L56_MAIN_POSTURE_MAX			255
#define CS35L56_MAIN_POSTURE_MASK			CS35L56_MAIN_POSTURE_MAX

/* Software Values */
#define CS35L56_HALO_STATE_SHUTDOWN			1
#define CS35L56_HALO_STATE_BOOT_DONE			2

#define CS35L56_MBOX_CMD_AUDIO_PLAY			0x0B000001
#define CS35L56_MBOX_CMD_AUDIO_PAUSE			0x0B000002
#define CS35L56_MBOX_CMD_HIBERNATE_NOW			0x02000001
#define CS35L56_MBOX_CMD_WAKEUP				0x02000002
#define CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE		0x02000003
#define CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE		0x02000004
#define CS35L56_MBOX_CMD_SHUTDOWN			0x02000005
#define CS35L56_MBOX_CMD_SYSTEM_RESET			0x02000007

#define CS35L56_MBOX_TIMEOUT_US				5000
#define CS35L56_MBOX_POLL_US				250

#define CS35L56_PS0_POLL_US				500
#define CS35L56_PS0_TIMEOUT_US				50000
#define CS35L56_PS3_POLL_US				500
#define CS35L56_PS3_TIMEOUT_US				300000

#define CS35L56_CONTROL_PORT_READY_US			2200
#define CS35L56_HALO_STATE_POLL_US			1000
#define CS35L56_HALO_STATE_TIMEOUT_US			50000
#define CS35L56_HIBERNATE_WAKE_POLL_US			500
#define CS35L56_HIBERNATE_WAKE_TIMEOUT_US		5000
#define CS35L56_RESET_PULSE_MIN_US			1100

#define CS35L56_SDW1_PLAYBACK_PORT			1
#define CS35L56_SDW1_CAPTURE_PORT			3

#define CS35L56_NUM_BULK_SUPPLIES			3
#define CS35L56_NUM_DSP_REGIONS				5

extern struct regmap_config cs35l56_regmap_i2c;
extern struct regmap_config cs35l56_regmap_spi;
extern struct regmap_config cs35l56_regmap_sdw;

extern const struct cs_dsp_region cs35l56_dsp1_regions[CS35L56_NUM_DSP_REGIONS];
extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];

void cs35l56_patch(struct device *dev, struct regmap *regmap, u8 revid);
void cs35l56_reread_firmware_registers(struct device *dev, struct regmap *regmap);
int cs35l56_get_bclk_freq_id(unsigned int freq);
void cs35l56_fill_supply_names(struct regulator_bulk_data *data);

#endif /* ifndef __CS35L56_H */
+40 −0
Original line number Diff line number Diff line
@@ -68,6 +68,9 @@ config SND_SOC_ALL_CODECS
	imply SND_SOC_CS35L41_I2C
	imply SND_SOC_CS35L45_I2C
	imply SND_SOC_CS35L45_SPI
	imply SND_SOC_CS35L56_I2C
	imply SND_SOC_CS35L56_SPI
	imply SND_SOC_CS35L56_SDW
	imply SND_SOC_CS42L42
	imply SND_SOC_CS42L42_SDW
	imply SND_SOC_CS42L51_I2C
@@ -366,6 +369,7 @@ config SND_SOC_WM_ADSP
	default y if SND_SOC_CS35L41_I2C=y
	default y if SND_SOC_CS35L45_SPI=y
	default y if SND_SOC_CS35L45_I2C=y
	default y if SND_SOC_CS35L56=y
	default m if SND_SOC_MADERA=m
	default m if SND_SOC_CS47L24=m
	default m if SND_SOC_WM5102=m
@@ -375,6 +379,7 @@ config SND_SOC_WM_ADSP
	default m if SND_SOC_CS35L41_I2C=m
	default m if SND_SOC_CS35L45_SPI=m
	default m if SND_SOC_CS35L45_I2C=m
	default m if SND_SOC_CS35L56=m

config SND_SOC_AB8500_CODEC
	tristate
@@ -715,6 +720,41 @@ config SND_SOC_CS35L45_I2C
	  Enable support for Cirrus Logic CS35L45 smart speaker amplifier
	  with I2C control.

config SND_SOC_CS35L56
	tristate

config SND_SOC_CS35L56_SHARED
	tristate

config SND_SOC_CS35L56_I2C
	tristate "Cirrus Logic CS35L56 CODEC (I2C)"
	depends on I2C
	depends on SOUNDWIRE || !SOUNDWIRE
	select REGMAP_I2C
	select SND_SOC_CS35L56
	select SND_SOC_CS35L56_SHARED
	help
	  Enable support for Cirrus Logic CS35L56 boosted amplifier with I2C control

config SND_SOC_CS35L56_SPI
	tristate "Cirrus Logic CS35L56 CODEC (SPI)"
	depends on SPI_MASTER
	depends on SOUNDWIRE || !SOUNDWIRE
	select REGMAP_SPI
	select SND_SOC_CS35L56
	select SND_SOC_CS35L56_SHARED
	help
	  Enable support for Cirrus Logic CS35L56 boosted amplifier with SPI control

config SND_SOC_CS35L56_SDW
	tristate "Cirrus Logic CS35L56 CODEC (SDW)"
	depends on SOUNDWIRE
	select REGMAP
	select SND_SOC_CS35L56
	select SND_SOC_CS35L56_SHARED
	help
	  Enable support for Cirrus Logic CS35L56 boosted amplifier with SoundWire control

config SND_SOC_CS42L42_CORE
	tristate

Loading