162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (c) 2015-2017, The Linux Foundation. 362306a36Sopenharmony_ci// Copyright (c) 2019, Linaro Limited 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/bitops.h> 662306a36Sopenharmony_ci#include <linux/gpio.h> 762306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/regmap.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1262306a36Sopenharmony_ci#include <linux/soundwire/sdw.h> 1362306a36Sopenharmony_ci#include <linux/soundwire/sdw_registers.h> 1462306a36Sopenharmony_ci#include <linux/soundwire/sdw_type.h> 1562306a36Sopenharmony_ci#include <sound/soc.h> 1662306a36Sopenharmony_ci#include <sound/tlv.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define WSA881X_DIGITAL_BASE 0x3000 1962306a36Sopenharmony_ci#define WSA881X_ANALOG_BASE 0x3100 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* Digital register address space */ 2262306a36Sopenharmony_ci#define WSA881X_CHIP_ID0 (WSA881X_DIGITAL_BASE + 0x0000) 2362306a36Sopenharmony_ci#define WSA881X_CHIP_ID1 (WSA881X_DIGITAL_BASE + 0x0001) 2462306a36Sopenharmony_ci#define WSA881X_CHIP_ID2 (WSA881X_DIGITAL_BASE + 0x0002) 2562306a36Sopenharmony_ci#define WSA881X_CHIP_ID3 (WSA881X_DIGITAL_BASE + 0x0003) 2662306a36Sopenharmony_ci#define WSA881X_BUS_ID (WSA881X_DIGITAL_BASE + 0x0004) 2762306a36Sopenharmony_ci#define WSA881X_CDC_RST_CTL (WSA881X_DIGITAL_BASE + 0x0005) 2862306a36Sopenharmony_ci#define WSA881X_CDC_TOP_CLK_CTL (WSA881X_DIGITAL_BASE + 0x0006) 2962306a36Sopenharmony_ci#define WSA881X_CDC_ANA_CLK_CTL (WSA881X_DIGITAL_BASE + 0x0007) 3062306a36Sopenharmony_ci#define WSA881X_CDC_DIG_CLK_CTL (WSA881X_DIGITAL_BASE + 0x0008) 3162306a36Sopenharmony_ci#define WSA881X_CLOCK_CONFIG (WSA881X_DIGITAL_BASE + 0x0009) 3262306a36Sopenharmony_ci#define WSA881X_ANA_CTL (WSA881X_DIGITAL_BASE + 0x000A) 3362306a36Sopenharmony_ci#define WSA881X_SWR_RESET_EN (WSA881X_DIGITAL_BASE + 0x000B) 3462306a36Sopenharmony_ci#define WSA881X_RESET_CTL (WSA881X_DIGITAL_BASE + 0x000C) 3562306a36Sopenharmony_ci#define WSA881X_TADC_VALUE_CTL (WSA881X_DIGITAL_BASE + 0x000F) 3662306a36Sopenharmony_ci#define WSA881X_TEMP_DETECT_CTL (WSA881X_DIGITAL_BASE + 0x0010) 3762306a36Sopenharmony_ci#define WSA881X_TEMP_MSB (WSA881X_DIGITAL_BASE + 0x0011) 3862306a36Sopenharmony_ci#define WSA881X_TEMP_LSB (WSA881X_DIGITAL_BASE + 0x0012) 3962306a36Sopenharmony_ci#define WSA881X_TEMP_CONFIG0 (WSA881X_DIGITAL_BASE + 0x0013) 4062306a36Sopenharmony_ci#define WSA881X_TEMP_CONFIG1 (WSA881X_DIGITAL_BASE + 0x0014) 4162306a36Sopenharmony_ci#define WSA881X_CDC_CLIP_CTL (WSA881X_DIGITAL_BASE + 0x0015) 4262306a36Sopenharmony_ci#define WSA881X_SDM_PDM9_LSB (WSA881X_DIGITAL_BASE + 0x0016) 4362306a36Sopenharmony_ci#define WSA881X_SDM_PDM9_MSB (WSA881X_DIGITAL_BASE + 0x0017) 4462306a36Sopenharmony_ci#define WSA881X_CDC_RX_CTL (WSA881X_DIGITAL_BASE + 0x0018) 4562306a36Sopenharmony_ci#define WSA881X_DEM_BYPASS_DATA0 (WSA881X_DIGITAL_BASE + 0x0019) 4662306a36Sopenharmony_ci#define WSA881X_DEM_BYPASS_DATA1 (WSA881X_DIGITAL_BASE + 0x001A) 4762306a36Sopenharmony_ci#define WSA881X_DEM_BYPASS_DATA2 (WSA881X_DIGITAL_BASE + 0x001B) 4862306a36Sopenharmony_ci#define WSA881X_DEM_BYPASS_DATA3 (WSA881X_DIGITAL_BASE + 0x001C) 4962306a36Sopenharmony_ci#define WSA881X_OTP_CTRL0 (WSA881X_DIGITAL_BASE + 0x001D) 5062306a36Sopenharmony_ci#define WSA881X_OTP_CTRL1 (WSA881X_DIGITAL_BASE + 0x001E) 5162306a36Sopenharmony_ci#define WSA881X_HDRIVE_CTL_GROUP1 (WSA881X_DIGITAL_BASE + 0x001F) 5262306a36Sopenharmony_ci#define WSA881X_INTR_MODE (WSA881X_DIGITAL_BASE + 0x0020) 5362306a36Sopenharmony_ci#define WSA881X_INTR_MASK (WSA881X_DIGITAL_BASE + 0x0021) 5462306a36Sopenharmony_ci#define WSA881X_INTR_STATUS (WSA881X_DIGITAL_BASE + 0x0022) 5562306a36Sopenharmony_ci#define WSA881X_INTR_CLEAR (WSA881X_DIGITAL_BASE + 0x0023) 5662306a36Sopenharmony_ci#define WSA881X_INTR_LEVEL (WSA881X_DIGITAL_BASE + 0x0024) 5762306a36Sopenharmony_ci#define WSA881X_INTR_SET (WSA881X_DIGITAL_BASE + 0x0025) 5862306a36Sopenharmony_ci#define WSA881X_INTR_TEST (WSA881X_DIGITAL_BASE + 0x0026) 5962306a36Sopenharmony_ci#define WSA881X_PDM_TEST_MODE (WSA881X_DIGITAL_BASE + 0x0030) 6062306a36Sopenharmony_ci#define WSA881X_ATE_TEST_MODE (WSA881X_DIGITAL_BASE + 0x0031) 6162306a36Sopenharmony_ci#define WSA881X_PIN_CTL_MODE (WSA881X_DIGITAL_BASE + 0x0032) 6262306a36Sopenharmony_ci#define WSA881X_PIN_CTL_OE (WSA881X_DIGITAL_BASE + 0x0033) 6362306a36Sopenharmony_ci#define WSA881X_PIN_WDATA_IOPAD (WSA881X_DIGITAL_BASE + 0x0034) 6462306a36Sopenharmony_ci#define WSA881X_PIN_STATUS (WSA881X_DIGITAL_BASE + 0x0035) 6562306a36Sopenharmony_ci#define WSA881X_DIG_DEBUG_MODE (WSA881X_DIGITAL_BASE + 0x0037) 6662306a36Sopenharmony_ci#define WSA881X_DIG_DEBUG_SEL (WSA881X_DIGITAL_BASE + 0x0038) 6762306a36Sopenharmony_ci#define WSA881X_DIG_DEBUG_EN (WSA881X_DIGITAL_BASE + 0x0039) 6862306a36Sopenharmony_ci#define WSA881X_SWR_HM_TEST1 (WSA881X_DIGITAL_BASE + 0x003B) 6962306a36Sopenharmony_ci#define WSA881X_SWR_HM_TEST2 (WSA881X_DIGITAL_BASE + 0x003C) 7062306a36Sopenharmony_ci#define WSA881X_TEMP_DETECT_DBG_CTL (WSA881X_DIGITAL_BASE + 0x003D) 7162306a36Sopenharmony_ci#define WSA881X_TEMP_DEBUG_MSB (WSA881X_DIGITAL_BASE + 0x003E) 7262306a36Sopenharmony_ci#define WSA881X_TEMP_DEBUG_LSB (WSA881X_DIGITAL_BASE + 0x003F) 7362306a36Sopenharmony_ci#define WSA881X_SAMPLE_EDGE_SEL (WSA881X_DIGITAL_BASE + 0x0044) 7462306a36Sopenharmony_ci#define WSA881X_IOPAD_CTL (WSA881X_DIGITAL_BASE + 0x0045) 7562306a36Sopenharmony_ci#define WSA881X_SPARE_0 (WSA881X_DIGITAL_BASE + 0x0050) 7662306a36Sopenharmony_ci#define WSA881X_SPARE_1 (WSA881X_DIGITAL_BASE + 0x0051) 7762306a36Sopenharmony_ci#define WSA881X_SPARE_2 (WSA881X_DIGITAL_BASE + 0x0052) 7862306a36Sopenharmony_ci#define WSA881X_OTP_REG_0 (WSA881X_DIGITAL_BASE + 0x0080) 7962306a36Sopenharmony_ci#define WSA881X_OTP_REG_1 (WSA881X_DIGITAL_BASE + 0x0081) 8062306a36Sopenharmony_ci#define WSA881X_OTP_REG_2 (WSA881X_DIGITAL_BASE + 0x0082) 8162306a36Sopenharmony_ci#define WSA881X_OTP_REG_3 (WSA881X_DIGITAL_BASE + 0x0083) 8262306a36Sopenharmony_ci#define WSA881X_OTP_REG_4 (WSA881X_DIGITAL_BASE + 0x0084) 8362306a36Sopenharmony_ci#define WSA881X_OTP_REG_5 (WSA881X_DIGITAL_BASE + 0x0085) 8462306a36Sopenharmony_ci#define WSA881X_OTP_REG_6 (WSA881X_DIGITAL_BASE + 0x0086) 8562306a36Sopenharmony_ci#define WSA881X_OTP_REG_7 (WSA881X_DIGITAL_BASE + 0x0087) 8662306a36Sopenharmony_ci#define WSA881X_OTP_REG_8 (WSA881X_DIGITAL_BASE + 0x0088) 8762306a36Sopenharmony_ci#define WSA881X_OTP_REG_9 (WSA881X_DIGITAL_BASE + 0x0089) 8862306a36Sopenharmony_ci#define WSA881X_OTP_REG_10 (WSA881X_DIGITAL_BASE + 0x008A) 8962306a36Sopenharmony_ci#define WSA881X_OTP_REG_11 (WSA881X_DIGITAL_BASE + 0x008B) 9062306a36Sopenharmony_ci#define WSA881X_OTP_REG_12 (WSA881X_DIGITAL_BASE + 0x008C) 9162306a36Sopenharmony_ci#define WSA881X_OTP_REG_13 (WSA881X_DIGITAL_BASE + 0x008D) 9262306a36Sopenharmony_ci#define WSA881X_OTP_REG_14 (WSA881X_DIGITAL_BASE + 0x008E) 9362306a36Sopenharmony_ci#define WSA881X_OTP_REG_15 (WSA881X_DIGITAL_BASE + 0x008F) 9462306a36Sopenharmony_ci#define WSA881X_OTP_REG_16 (WSA881X_DIGITAL_BASE + 0x0090) 9562306a36Sopenharmony_ci#define WSA881X_OTP_REG_17 (WSA881X_DIGITAL_BASE + 0x0091) 9662306a36Sopenharmony_ci#define WSA881X_OTP_REG_18 (WSA881X_DIGITAL_BASE + 0x0092) 9762306a36Sopenharmony_ci#define WSA881X_OTP_REG_19 (WSA881X_DIGITAL_BASE + 0x0093) 9862306a36Sopenharmony_ci#define WSA881X_OTP_REG_20 (WSA881X_DIGITAL_BASE + 0x0094) 9962306a36Sopenharmony_ci#define WSA881X_OTP_REG_21 (WSA881X_DIGITAL_BASE + 0x0095) 10062306a36Sopenharmony_ci#define WSA881X_OTP_REG_22 (WSA881X_DIGITAL_BASE + 0x0096) 10162306a36Sopenharmony_ci#define WSA881X_OTP_REG_23 (WSA881X_DIGITAL_BASE + 0x0097) 10262306a36Sopenharmony_ci#define WSA881X_OTP_REG_24 (WSA881X_DIGITAL_BASE + 0x0098) 10362306a36Sopenharmony_ci#define WSA881X_OTP_REG_25 (WSA881X_DIGITAL_BASE + 0x0099) 10462306a36Sopenharmony_ci#define WSA881X_OTP_REG_26 (WSA881X_DIGITAL_BASE + 0x009A) 10562306a36Sopenharmony_ci#define WSA881X_OTP_REG_27 (WSA881X_DIGITAL_BASE + 0x009B) 10662306a36Sopenharmony_ci#define WSA881X_OTP_REG_28 (WSA881X_DIGITAL_BASE + 0x009C) 10762306a36Sopenharmony_ci#define WSA881X_OTP_REG_29 (WSA881X_DIGITAL_BASE + 0x009D) 10862306a36Sopenharmony_ci#define WSA881X_OTP_REG_30 (WSA881X_DIGITAL_BASE + 0x009E) 10962306a36Sopenharmony_ci#define WSA881X_OTP_REG_31 (WSA881X_DIGITAL_BASE + 0x009F) 11062306a36Sopenharmony_ci#define WSA881X_OTP_REG_63 (WSA881X_DIGITAL_BASE + 0x00BF) 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* Analog Register address space */ 11362306a36Sopenharmony_ci#define WSA881X_BIAS_REF_CTRL (WSA881X_ANALOG_BASE + 0x0000) 11462306a36Sopenharmony_ci#define WSA881X_BIAS_TEST (WSA881X_ANALOG_BASE + 0x0001) 11562306a36Sopenharmony_ci#define WSA881X_BIAS_BIAS (WSA881X_ANALOG_BASE + 0x0002) 11662306a36Sopenharmony_ci#define WSA881X_TEMP_OP (WSA881X_ANALOG_BASE + 0x0003) 11762306a36Sopenharmony_ci#define WSA881X_TEMP_IREF_CTRL (WSA881X_ANALOG_BASE + 0x0004) 11862306a36Sopenharmony_ci#define WSA881X_TEMP_ISENS_CTRL (WSA881X_ANALOG_BASE + 0x0005) 11962306a36Sopenharmony_ci#define WSA881X_TEMP_CLK_CTRL (WSA881X_ANALOG_BASE + 0x0006) 12062306a36Sopenharmony_ci#define WSA881X_TEMP_TEST (WSA881X_ANALOG_BASE + 0x0007) 12162306a36Sopenharmony_ci#define WSA881X_TEMP_BIAS (WSA881X_ANALOG_BASE + 0x0008) 12262306a36Sopenharmony_ci#define WSA881X_TEMP_ADC_CTRL (WSA881X_ANALOG_BASE + 0x0009) 12362306a36Sopenharmony_ci#define WSA881X_TEMP_DOUT_MSB (WSA881X_ANALOG_BASE + 0x000A) 12462306a36Sopenharmony_ci#define WSA881X_TEMP_DOUT_LSB (WSA881X_ANALOG_BASE + 0x000B) 12562306a36Sopenharmony_ci#define WSA881X_ADC_EN_MODU_V (WSA881X_ANALOG_BASE + 0x0010) 12662306a36Sopenharmony_ci#define WSA881X_ADC_EN_MODU_I (WSA881X_ANALOG_BASE + 0x0011) 12762306a36Sopenharmony_ci#define WSA881X_ADC_EN_DET_TEST_V (WSA881X_ANALOG_BASE + 0x0012) 12862306a36Sopenharmony_ci#define WSA881X_ADC_EN_DET_TEST_I (WSA881X_ANALOG_BASE + 0x0013) 12962306a36Sopenharmony_ci#define WSA881X_ADC_SEL_IBIAS (WSA881X_ANALOG_BASE + 0x0014) 13062306a36Sopenharmony_ci#define WSA881X_ADC_EN_SEL_IBAIS (WSA881X_ANALOG_BASE + 0x0015) 13162306a36Sopenharmony_ci#define WSA881X_SPKR_DRV_EN (WSA881X_ANALOG_BASE + 0x001A) 13262306a36Sopenharmony_ci#define WSA881X_SPKR_DRV_GAIN (WSA881X_ANALOG_BASE + 0x001B) 13362306a36Sopenharmony_ci#define WSA881X_PA_GAIN_SEL_MASK BIT(3) 13462306a36Sopenharmony_ci#define WSA881X_PA_GAIN_SEL_REG BIT(3) 13562306a36Sopenharmony_ci#define WSA881X_PA_GAIN_SEL_DRE 0 13662306a36Sopenharmony_ci#define WSA881X_SPKR_PAG_GAIN_MASK GENMASK(7, 4) 13762306a36Sopenharmony_ci#define WSA881X_SPKR_DAC_CTL (WSA881X_ANALOG_BASE + 0x001C) 13862306a36Sopenharmony_ci#define WSA881X_SPKR_DRV_DBG (WSA881X_ANALOG_BASE + 0x001D) 13962306a36Sopenharmony_ci#define WSA881X_SPKR_PWRSTG_DBG (WSA881X_ANALOG_BASE + 0x001E) 14062306a36Sopenharmony_ci#define WSA881X_SPKR_OCP_CTL (WSA881X_ANALOG_BASE + 0x001F) 14162306a36Sopenharmony_ci#define WSA881X_SPKR_OCP_MASK GENMASK(7, 6) 14262306a36Sopenharmony_ci#define WSA881X_SPKR_OCP_EN BIT(7) 14362306a36Sopenharmony_ci#define WSA881X_SPKR_OCP_HOLD BIT(6) 14462306a36Sopenharmony_ci#define WSA881X_SPKR_CLIP_CTL (WSA881X_ANALOG_BASE + 0x0020) 14562306a36Sopenharmony_ci#define WSA881X_SPKR_BBM_CTL (WSA881X_ANALOG_BASE + 0x0021) 14662306a36Sopenharmony_ci#define WSA881X_SPKR_MISC_CTL1 (WSA881X_ANALOG_BASE + 0x0022) 14762306a36Sopenharmony_ci#define WSA881X_SPKR_MISC_CTL2 (WSA881X_ANALOG_BASE + 0x0023) 14862306a36Sopenharmony_ci#define WSA881X_SPKR_BIAS_INT (WSA881X_ANALOG_BASE + 0x0024) 14962306a36Sopenharmony_ci#define WSA881X_SPKR_PA_INT (WSA881X_ANALOG_BASE + 0x0025) 15062306a36Sopenharmony_ci#define WSA881X_SPKR_BIAS_CAL (WSA881X_ANALOG_BASE + 0x0026) 15162306a36Sopenharmony_ci#define WSA881X_SPKR_BIAS_PSRR (WSA881X_ANALOG_BASE + 0x0027) 15262306a36Sopenharmony_ci#define WSA881X_SPKR_STATUS1 (WSA881X_ANALOG_BASE + 0x0028) 15362306a36Sopenharmony_ci#define WSA881X_SPKR_STATUS2 (WSA881X_ANALOG_BASE + 0x0029) 15462306a36Sopenharmony_ci#define WSA881X_BOOST_EN_CTL (WSA881X_ANALOG_BASE + 0x002A) 15562306a36Sopenharmony_ci#define WSA881X_BOOST_EN_MASK BIT(7) 15662306a36Sopenharmony_ci#define WSA881X_BOOST_EN BIT(7) 15762306a36Sopenharmony_ci#define WSA881X_BOOST_CURRENT_LIMIT (WSA881X_ANALOG_BASE + 0x002B) 15862306a36Sopenharmony_ci#define WSA881X_BOOST_PS_CTL (WSA881X_ANALOG_BASE + 0x002C) 15962306a36Sopenharmony_ci#define WSA881X_BOOST_PRESET_OUT1 (WSA881X_ANALOG_BASE + 0x002D) 16062306a36Sopenharmony_ci#define WSA881X_BOOST_PRESET_OUT2 (WSA881X_ANALOG_BASE + 0x002E) 16162306a36Sopenharmony_ci#define WSA881X_BOOST_FORCE_OUT (WSA881X_ANALOG_BASE + 0x002F) 16262306a36Sopenharmony_ci#define WSA881X_BOOST_LDO_PROG (WSA881X_ANALOG_BASE + 0x0030) 16362306a36Sopenharmony_ci#define WSA881X_BOOST_SLOPE_COMP_ISENSE_FB (WSA881X_ANALOG_BASE + 0x0031) 16462306a36Sopenharmony_ci#define WSA881X_BOOST_RON_CTL (WSA881X_ANALOG_BASE + 0x0032) 16562306a36Sopenharmony_ci#define WSA881X_BOOST_LOOP_STABILITY (WSA881X_ANALOG_BASE + 0x0033) 16662306a36Sopenharmony_ci#define WSA881X_BOOST_ZX_CTL (WSA881X_ANALOG_BASE + 0x0034) 16762306a36Sopenharmony_ci#define WSA881X_BOOST_START_CTL (WSA881X_ANALOG_BASE + 0x0035) 16862306a36Sopenharmony_ci#define WSA881X_BOOST_MISC1_CTL (WSA881X_ANALOG_BASE + 0x0036) 16962306a36Sopenharmony_ci#define WSA881X_BOOST_MISC2_CTL (WSA881X_ANALOG_BASE + 0x0037) 17062306a36Sopenharmony_ci#define WSA881X_BOOST_MISC3_CTL (WSA881X_ANALOG_BASE + 0x0038) 17162306a36Sopenharmony_ci#define WSA881X_BOOST_ATEST_CTL (WSA881X_ANALOG_BASE + 0x0039) 17262306a36Sopenharmony_ci#define WSA881X_SPKR_PROT_FE_GAIN (WSA881X_ANALOG_BASE + 0x003A) 17362306a36Sopenharmony_ci#define WSA881X_SPKR_PROT_FE_CM_LDO_SET (WSA881X_ANALOG_BASE + 0x003B) 17462306a36Sopenharmony_ci#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1 (WSA881X_ANALOG_BASE + 0x003C) 17562306a36Sopenharmony_ci#define WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2 (WSA881X_ANALOG_BASE + 0x003D) 17662306a36Sopenharmony_ci#define WSA881X_SPKR_PROT_ATEST1 (WSA881X_ANALOG_BASE + 0x003E) 17762306a36Sopenharmony_ci#define WSA881X_SPKR_PROT_ATEST2 (WSA881X_ANALOG_BASE + 0x003F) 17862306a36Sopenharmony_ci#define WSA881X_SPKR_PROT_FE_VSENSE_VCM (WSA881X_ANALOG_BASE + 0x0040) 17962306a36Sopenharmony_ci#define WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1 (WSA881X_ANALOG_BASE + 0x0041) 18062306a36Sopenharmony_ci#define WSA881X_BONGO_RESRV_REG1 (WSA881X_ANALOG_BASE + 0x0042) 18162306a36Sopenharmony_ci#define WSA881X_BONGO_RESRV_REG2 (WSA881X_ANALOG_BASE + 0x0043) 18262306a36Sopenharmony_ci#define WSA881X_SPKR_PROT_SAR (WSA881X_ANALOG_BASE + 0x0044) 18362306a36Sopenharmony_ci#define WSA881X_SPKR_STATUS3 (WSA881X_ANALOG_BASE + 0x0045) 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci#define SWRS_SCP_FRAME_CTRL_BANK(m) (0x60 + 0x10 * (m)) 18662306a36Sopenharmony_ci#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m)) 18762306a36Sopenharmony_ci#define SWR_SLV_MAX_REG_ADDR 0x390 18862306a36Sopenharmony_ci#define SWR_SLV_START_REG_ADDR 0x40 18962306a36Sopenharmony_ci#define SWR_SLV_MAX_BUF_LEN 20 19062306a36Sopenharmony_ci#define BYTES_PER_LINE 12 19162306a36Sopenharmony_ci#define SWR_SLV_RD_BUF_LEN 8 19262306a36Sopenharmony_ci#define SWR_SLV_WR_BUF_LEN 32 19362306a36Sopenharmony_ci#define SWR_SLV_MAX_DEVICES 2 19462306a36Sopenharmony_ci#define WSA881X_MAX_SWR_PORTS 4 19562306a36Sopenharmony_ci#define WSA881X_VERSION_ENTRY_SIZE 27 19662306a36Sopenharmony_ci#define WSA881X_OCP_CTL_TIMER_SEC 2 19762306a36Sopenharmony_ci#define WSA881X_OCP_CTL_TEMP_CELSIUS 25 19862306a36Sopenharmony_ci#define WSA881X_OCP_CTL_POLL_TIMER_SEC 60 19962306a36Sopenharmony_ci#define WSA881X_PROBE_TIMEOUT 1000 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci#define WSA881X_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ 20262306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 20362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ 20462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_READWRITE,\ 20562306a36Sopenharmony_ci .tlv.p = (tlv_array), \ 20662306a36Sopenharmony_ci .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ 20762306a36Sopenharmony_ci .put = wsa881x_put_pa_gain, \ 20862306a36Sopenharmony_ci .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic struct reg_default wsa881x_defaults[] = { 21162306a36Sopenharmony_ci { WSA881X_CHIP_ID0, 0x00 }, 21262306a36Sopenharmony_ci { WSA881X_CHIP_ID1, 0x00 }, 21362306a36Sopenharmony_ci { WSA881X_CHIP_ID2, 0x00 }, 21462306a36Sopenharmony_ci { WSA881X_CHIP_ID3, 0x02 }, 21562306a36Sopenharmony_ci { WSA881X_BUS_ID, 0x00 }, 21662306a36Sopenharmony_ci { WSA881X_CDC_RST_CTL, 0x00 }, 21762306a36Sopenharmony_ci { WSA881X_CDC_TOP_CLK_CTL, 0x03 }, 21862306a36Sopenharmony_ci { WSA881X_CDC_ANA_CLK_CTL, 0x00 }, 21962306a36Sopenharmony_ci { WSA881X_CDC_DIG_CLK_CTL, 0x00 }, 22062306a36Sopenharmony_ci { WSA881X_CLOCK_CONFIG, 0x00 }, 22162306a36Sopenharmony_ci { WSA881X_ANA_CTL, 0x08 }, 22262306a36Sopenharmony_ci { WSA881X_SWR_RESET_EN, 0x00 }, 22362306a36Sopenharmony_ci { WSA881X_TEMP_DETECT_CTL, 0x01 }, 22462306a36Sopenharmony_ci { WSA881X_TEMP_MSB, 0x00 }, 22562306a36Sopenharmony_ci { WSA881X_TEMP_LSB, 0x00 }, 22662306a36Sopenharmony_ci { WSA881X_TEMP_CONFIG0, 0x00 }, 22762306a36Sopenharmony_ci { WSA881X_TEMP_CONFIG1, 0x00 }, 22862306a36Sopenharmony_ci { WSA881X_CDC_CLIP_CTL, 0x03 }, 22962306a36Sopenharmony_ci { WSA881X_SDM_PDM9_LSB, 0x00 }, 23062306a36Sopenharmony_ci { WSA881X_SDM_PDM9_MSB, 0x00 }, 23162306a36Sopenharmony_ci { WSA881X_CDC_RX_CTL, 0x7E }, 23262306a36Sopenharmony_ci { WSA881X_DEM_BYPASS_DATA0, 0x00 }, 23362306a36Sopenharmony_ci { WSA881X_DEM_BYPASS_DATA1, 0x00 }, 23462306a36Sopenharmony_ci { WSA881X_DEM_BYPASS_DATA2, 0x00 }, 23562306a36Sopenharmony_ci { WSA881X_DEM_BYPASS_DATA3, 0x00 }, 23662306a36Sopenharmony_ci { WSA881X_OTP_CTRL0, 0x00 }, 23762306a36Sopenharmony_ci { WSA881X_OTP_CTRL1, 0x00 }, 23862306a36Sopenharmony_ci { WSA881X_HDRIVE_CTL_GROUP1, 0x00 }, 23962306a36Sopenharmony_ci { WSA881X_INTR_MODE, 0x00 }, 24062306a36Sopenharmony_ci { WSA881X_INTR_STATUS, 0x00 }, 24162306a36Sopenharmony_ci { WSA881X_INTR_CLEAR, 0x00 }, 24262306a36Sopenharmony_ci { WSA881X_INTR_LEVEL, 0x00 }, 24362306a36Sopenharmony_ci { WSA881X_INTR_SET, 0x00 }, 24462306a36Sopenharmony_ci { WSA881X_INTR_TEST, 0x00 }, 24562306a36Sopenharmony_ci { WSA881X_PDM_TEST_MODE, 0x00 }, 24662306a36Sopenharmony_ci { WSA881X_ATE_TEST_MODE, 0x00 }, 24762306a36Sopenharmony_ci { WSA881X_PIN_CTL_MODE, 0x00 }, 24862306a36Sopenharmony_ci { WSA881X_PIN_CTL_OE, 0x00 }, 24962306a36Sopenharmony_ci { WSA881X_PIN_WDATA_IOPAD, 0x00 }, 25062306a36Sopenharmony_ci { WSA881X_PIN_STATUS, 0x00 }, 25162306a36Sopenharmony_ci { WSA881X_DIG_DEBUG_MODE, 0x00 }, 25262306a36Sopenharmony_ci { WSA881X_DIG_DEBUG_SEL, 0x00 }, 25362306a36Sopenharmony_ci { WSA881X_DIG_DEBUG_EN, 0x00 }, 25462306a36Sopenharmony_ci { WSA881X_SWR_HM_TEST1, 0x08 }, 25562306a36Sopenharmony_ci { WSA881X_SWR_HM_TEST2, 0x00 }, 25662306a36Sopenharmony_ci { WSA881X_TEMP_DETECT_DBG_CTL, 0x00 }, 25762306a36Sopenharmony_ci { WSA881X_TEMP_DEBUG_MSB, 0x00 }, 25862306a36Sopenharmony_ci { WSA881X_TEMP_DEBUG_LSB, 0x00 }, 25962306a36Sopenharmony_ci { WSA881X_SAMPLE_EDGE_SEL, 0x0C }, 26062306a36Sopenharmony_ci { WSA881X_SPARE_0, 0x00 }, 26162306a36Sopenharmony_ci { WSA881X_SPARE_1, 0x00 }, 26262306a36Sopenharmony_ci { WSA881X_SPARE_2, 0x00 }, 26362306a36Sopenharmony_ci { WSA881X_OTP_REG_0, 0x01 }, 26462306a36Sopenharmony_ci { WSA881X_OTP_REG_1, 0xFF }, 26562306a36Sopenharmony_ci { WSA881X_OTP_REG_2, 0xC0 }, 26662306a36Sopenharmony_ci { WSA881X_OTP_REG_3, 0xFF }, 26762306a36Sopenharmony_ci { WSA881X_OTP_REG_4, 0xC0 }, 26862306a36Sopenharmony_ci { WSA881X_OTP_REG_5, 0xFF }, 26962306a36Sopenharmony_ci { WSA881X_OTP_REG_6, 0xFF }, 27062306a36Sopenharmony_ci { WSA881X_OTP_REG_7, 0xFF }, 27162306a36Sopenharmony_ci { WSA881X_OTP_REG_8, 0xFF }, 27262306a36Sopenharmony_ci { WSA881X_OTP_REG_9, 0xFF }, 27362306a36Sopenharmony_ci { WSA881X_OTP_REG_10, 0xFF }, 27462306a36Sopenharmony_ci { WSA881X_OTP_REG_11, 0xFF }, 27562306a36Sopenharmony_ci { WSA881X_OTP_REG_12, 0xFF }, 27662306a36Sopenharmony_ci { WSA881X_OTP_REG_13, 0xFF }, 27762306a36Sopenharmony_ci { WSA881X_OTP_REG_14, 0xFF }, 27862306a36Sopenharmony_ci { WSA881X_OTP_REG_15, 0xFF }, 27962306a36Sopenharmony_ci { WSA881X_OTP_REG_16, 0xFF }, 28062306a36Sopenharmony_ci { WSA881X_OTP_REG_17, 0xFF }, 28162306a36Sopenharmony_ci { WSA881X_OTP_REG_18, 0xFF }, 28262306a36Sopenharmony_ci { WSA881X_OTP_REG_19, 0xFF }, 28362306a36Sopenharmony_ci { WSA881X_OTP_REG_20, 0xFF }, 28462306a36Sopenharmony_ci { WSA881X_OTP_REG_21, 0xFF }, 28562306a36Sopenharmony_ci { WSA881X_OTP_REG_22, 0xFF }, 28662306a36Sopenharmony_ci { WSA881X_OTP_REG_23, 0xFF }, 28762306a36Sopenharmony_ci { WSA881X_OTP_REG_24, 0x03 }, 28862306a36Sopenharmony_ci { WSA881X_OTP_REG_25, 0x01 }, 28962306a36Sopenharmony_ci { WSA881X_OTP_REG_26, 0x03 }, 29062306a36Sopenharmony_ci { WSA881X_OTP_REG_27, 0x11 }, 29162306a36Sopenharmony_ci { WSA881X_OTP_REG_63, 0x40 }, 29262306a36Sopenharmony_ci /* WSA881x Analog registers */ 29362306a36Sopenharmony_ci { WSA881X_BIAS_REF_CTRL, 0x6C }, 29462306a36Sopenharmony_ci { WSA881X_BIAS_TEST, 0x16 }, 29562306a36Sopenharmony_ci { WSA881X_BIAS_BIAS, 0xF0 }, 29662306a36Sopenharmony_ci { WSA881X_TEMP_OP, 0x00 }, 29762306a36Sopenharmony_ci { WSA881X_TEMP_IREF_CTRL, 0x56 }, 29862306a36Sopenharmony_ci { WSA881X_TEMP_ISENS_CTRL, 0x47 }, 29962306a36Sopenharmony_ci { WSA881X_TEMP_CLK_CTRL, 0x87 }, 30062306a36Sopenharmony_ci { WSA881X_TEMP_TEST, 0x00 }, 30162306a36Sopenharmony_ci { WSA881X_TEMP_BIAS, 0x51 }, 30262306a36Sopenharmony_ci { WSA881X_TEMP_DOUT_MSB, 0x00 }, 30362306a36Sopenharmony_ci { WSA881X_TEMP_DOUT_LSB, 0x00 }, 30462306a36Sopenharmony_ci { WSA881X_ADC_EN_MODU_V, 0x00 }, 30562306a36Sopenharmony_ci { WSA881X_ADC_EN_MODU_I, 0x00 }, 30662306a36Sopenharmony_ci { WSA881X_ADC_EN_DET_TEST_V, 0x00 }, 30762306a36Sopenharmony_ci { WSA881X_ADC_EN_DET_TEST_I, 0x00 }, 30862306a36Sopenharmony_ci { WSA881X_ADC_EN_SEL_IBAIS, 0x10 }, 30962306a36Sopenharmony_ci { WSA881X_SPKR_DRV_EN, 0x74 }, 31062306a36Sopenharmony_ci { WSA881X_SPKR_DRV_DBG, 0x15 }, 31162306a36Sopenharmony_ci { WSA881X_SPKR_PWRSTG_DBG, 0x00 }, 31262306a36Sopenharmony_ci { WSA881X_SPKR_OCP_CTL, 0xD4 }, 31362306a36Sopenharmony_ci { WSA881X_SPKR_CLIP_CTL, 0x90 }, 31462306a36Sopenharmony_ci { WSA881X_SPKR_PA_INT, 0x54 }, 31562306a36Sopenharmony_ci { WSA881X_SPKR_BIAS_CAL, 0xAC }, 31662306a36Sopenharmony_ci { WSA881X_SPKR_STATUS1, 0x00 }, 31762306a36Sopenharmony_ci { WSA881X_SPKR_STATUS2, 0x00 }, 31862306a36Sopenharmony_ci { WSA881X_BOOST_EN_CTL, 0x18 }, 31962306a36Sopenharmony_ci { WSA881X_BOOST_CURRENT_LIMIT, 0x7A }, 32062306a36Sopenharmony_ci { WSA881X_BOOST_PRESET_OUT2, 0x70 }, 32162306a36Sopenharmony_ci { WSA881X_BOOST_FORCE_OUT, 0x0E }, 32262306a36Sopenharmony_ci { WSA881X_BOOST_LDO_PROG, 0x16 }, 32362306a36Sopenharmony_ci { WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x71 }, 32462306a36Sopenharmony_ci { WSA881X_BOOST_RON_CTL, 0x0F }, 32562306a36Sopenharmony_ci { WSA881X_BOOST_ZX_CTL, 0x34 }, 32662306a36Sopenharmony_ci { WSA881X_BOOST_START_CTL, 0x23 }, 32762306a36Sopenharmony_ci { WSA881X_BOOST_MISC1_CTL, 0x80 }, 32862306a36Sopenharmony_ci { WSA881X_BOOST_MISC2_CTL, 0x00 }, 32962306a36Sopenharmony_ci { WSA881X_BOOST_MISC3_CTL, 0x00 }, 33062306a36Sopenharmony_ci { WSA881X_BOOST_ATEST_CTL, 0x00 }, 33162306a36Sopenharmony_ci { WSA881X_SPKR_PROT_FE_GAIN, 0x46 }, 33262306a36Sopenharmony_ci { WSA881X_SPKR_PROT_FE_CM_LDO_SET, 0x3B }, 33362306a36Sopenharmony_ci { WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1, 0x8D }, 33462306a36Sopenharmony_ci { WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2, 0x8D }, 33562306a36Sopenharmony_ci { WSA881X_SPKR_PROT_ATEST1, 0x01 }, 33662306a36Sopenharmony_ci { WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x8D }, 33762306a36Sopenharmony_ci { WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1, 0x4D }, 33862306a36Sopenharmony_ci { WSA881X_SPKR_PROT_SAR, 0x00 }, 33962306a36Sopenharmony_ci { WSA881X_SPKR_STATUS3, 0x00 }, 34062306a36Sopenharmony_ci}; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic const struct reg_sequence wsa881x_pre_pmu_pa_2_0[] = { 34362306a36Sopenharmony_ci { WSA881X_SPKR_DRV_GAIN, 0x41, 0 }, 34462306a36Sopenharmony_ci { WSA881X_SPKR_MISC_CTL1, 0x87, 0 }, 34562306a36Sopenharmony_ci}; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic const struct reg_sequence wsa881x_vi_txfe_en_2_0[] = { 34862306a36Sopenharmony_ci { WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0 }, 34962306a36Sopenharmony_ci { WSA881X_SPKR_PROT_ATEST2, 0x0A, 0 }, 35062306a36Sopenharmony_ci { WSA881X_SPKR_PROT_FE_GAIN, 0x47, 0 }, 35162306a36Sopenharmony_ci}; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci/* Default register reset values for WSA881x rev 2.0 */ 35462306a36Sopenharmony_cistatic struct reg_sequence wsa881x_rev_2_0[] = { 35562306a36Sopenharmony_ci { WSA881X_RESET_CTL, 0x00, 0x00 }, 35662306a36Sopenharmony_ci { WSA881X_TADC_VALUE_CTL, 0x01, 0x00 }, 35762306a36Sopenharmony_ci { WSA881X_INTR_MASK, 0x1B, 0x00 }, 35862306a36Sopenharmony_ci { WSA881X_IOPAD_CTL, 0x00, 0x00 }, 35962306a36Sopenharmony_ci { WSA881X_OTP_REG_28, 0x3F, 0x00 }, 36062306a36Sopenharmony_ci { WSA881X_OTP_REG_29, 0x3F, 0x00 }, 36162306a36Sopenharmony_ci { WSA881X_OTP_REG_30, 0x01, 0x00 }, 36262306a36Sopenharmony_ci { WSA881X_OTP_REG_31, 0x01, 0x00 }, 36362306a36Sopenharmony_ci { WSA881X_TEMP_ADC_CTRL, 0x03, 0x00 }, 36462306a36Sopenharmony_ci { WSA881X_ADC_SEL_IBIAS, 0x45, 0x00 }, 36562306a36Sopenharmony_ci { WSA881X_SPKR_DRV_GAIN, 0xC1, 0x00 }, 36662306a36Sopenharmony_ci { WSA881X_SPKR_DAC_CTL, 0x42, 0x00 }, 36762306a36Sopenharmony_ci { WSA881X_SPKR_BBM_CTL, 0x02, 0x00 }, 36862306a36Sopenharmony_ci { WSA881X_SPKR_MISC_CTL1, 0x40, 0x00 }, 36962306a36Sopenharmony_ci { WSA881X_SPKR_MISC_CTL2, 0x07, 0x00 }, 37062306a36Sopenharmony_ci { WSA881X_SPKR_BIAS_INT, 0x5F, 0x00 }, 37162306a36Sopenharmony_ci { WSA881X_SPKR_BIAS_PSRR, 0x44, 0x00 }, 37262306a36Sopenharmony_ci { WSA881X_BOOST_PS_CTL, 0xA0, 0x00 }, 37362306a36Sopenharmony_ci { WSA881X_BOOST_PRESET_OUT1, 0xB7, 0x00 }, 37462306a36Sopenharmony_ci { WSA881X_BOOST_LOOP_STABILITY, 0x8D, 0x00 }, 37562306a36Sopenharmony_ci { WSA881X_SPKR_PROT_ATEST2, 0x02, 0x00 }, 37662306a36Sopenharmony_ci { WSA881X_BONGO_RESRV_REG1, 0x5E, 0x00 }, 37762306a36Sopenharmony_ci { WSA881X_BONGO_RESRV_REG2, 0x07, 0x00 }, 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cienum wsa_port_ids { 38162306a36Sopenharmony_ci WSA881X_PORT_DAC, 38262306a36Sopenharmony_ci WSA881X_PORT_COMP, 38362306a36Sopenharmony_ci WSA881X_PORT_BOOST, 38462306a36Sopenharmony_ci WSA881X_PORT_VISENSE, 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci/* 4 ports */ 38862306a36Sopenharmony_cistatic struct sdw_dpn_prop wsa_sink_dpn_prop[WSA881X_MAX_SWR_PORTS] = { 38962306a36Sopenharmony_ci { 39062306a36Sopenharmony_ci /* DAC */ 39162306a36Sopenharmony_ci .num = 1, 39262306a36Sopenharmony_ci .type = SDW_DPN_SIMPLE, 39362306a36Sopenharmony_ci .min_ch = 1, 39462306a36Sopenharmony_ci .max_ch = 1, 39562306a36Sopenharmony_ci .simple_ch_prep_sm = true, 39662306a36Sopenharmony_ci .read_only_wordlength = true, 39762306a36Sopenharmony_ci }, { 39862306a36Sopenharmony_ci /* COMP */ 39962306a36Sopenharmony_ci .num = 2, 40062306a36Sopenharmony_ci .type = SDW_DPN_SIMPLE, 40162306a36Sopenharmony_ci .min_ch = 1, 40262306a36Sopenharmony_ci .max_ch = 1, 40362306a36Sopenharmony_ci .simple_ch_prep_sm = true, 40462306a36Sopenharmony_ci .read_only_wordlength = true, 40562306a36Sopenharmony_ci }, { 40662306a36Sopenharmony_ci /* BOOST */ 40762306a36Sopenharmony_ci .num = 3, 40862306a36Sopenharmony_ci .type = SDW_DPN_SIMPLE, 40962306a36Sopenharmony_ci .min_ch = 1, 41062306a36Sopenharmony_ci .max_ch = 1, 41162306a36Sopenharmony_ci .simple_ch_prep_sm = true, 41262306a36Sopenharmony_ci .read_only_wordlength = true, 41362306a36Sopenharmony_ci }, { 41462306a36Sopenharmony_ci /* VISENSE */ 41562306a36Sopenharmony_ci .num = 4, 41662306a36Sopenharmony_ci .type = SDW_DPN_SIMPLE, 41762306a36Sopenharmony_ci .min_ch = 1, 41862306a36Sopenharmony_ci .max_ch = 1, 41962306a36Sopenharmony_ci .simple_ch_prep_sm = true, 42062306a36Sopenharmony_ci .read_only_wordlength = true, 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci}; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic const struct sdw_port_config wsa881x_pconfig[WSA881X_MAX_SWR_PORTS] = { 42562306a36Sopenharmony_ci { 42662306a36Sopenharmony_ci .num = 1, 42762306a36Sopenharmony_ci .ch_mask = 0x1, 42862306a36Sopenharmony_ci }, { 42962306a36Sopenharmony_ci .num = 2, 43062306a36Sopenharmony_ci .ch_mask = 0xf, 43162306a36Sopenharmony_ci }, { 43262306a36Sopenharmony_ci .num = 3, 43362306a36Sopenharmony_ci .ch_mask = 0x3, 43462306a36Sopenharmony_ci }, { /* IV feedback */ 43562306a36Sopenharmony_ci .num = 4, 43662306a36Sopenharmony_ci .ch_mask = 0x3, 43762306a36Sopenharmony_ci }, 43862306a36Sopenharmony_ci}; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic bool wsa881x_readable_register(struct device *dev, unsigned int reg) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci switch (reg) { 44362306a36Sopenharmony_ci case WSA881X_CHIP_ID0: 44462306a36Sopenharmony_ci case WSA881X_CHIP_ID1: 44562306a36Sopenharmony_ci case WSA881X_CHIP_ID2: 44662306a36Sopenharmony_ci case WSA881X_CHIP_ID3: 44762306a36Sopenharmony_ci case WSA881X_BUS_ID: 44862306a36Sopenharmony_ci case WSA881X_CDC_RST_CTL: 44962306a36Sopenharmony_ci case WSA881X_CDC_TOP_CLK_CTL: 45062306a36Sopenharmony_ci case WSA881X_CDC_ANA_CLK_CTL: 45162306a36Sopenharmony_ci case WSA881X_CDC_DIG_CLK_CTL: 45262306a36Sopenharmony_ci case WSA881X_CLOCK_CONFIG: 45362306a36Sopenharmony_ci case WSA881X_ANA_CTL: 45462306a36Sopenharmony_ci case WSA881X_SWR_RESET_EN: 45562306a36Sopenharmony_ci case WSA881X_RESET_CTL: 45662306a36Sopenharmony_ci case WSA881X_TADC_VALUE_CTL: 45762306a36Sopenharmony_ci case WSA881X_TEMP_DETECT_CTL: 45862306a36Sopenharmony_ci case WSA881X_TEMP_MSB: 45962306a36Sopenharmony_ci case WSA881X_TEMP_LSB: 46062306a36Sopenharmony_ci case WSA881X_TEMP_CONFIG0: 46162306a36Sopenharmony_ci case WSA881X_TEMP_CONFIG1: 46262306a36Sopenharmony_ci case WSA881X_CDC_CLIP_CTL: 46362306a36Sopenharmony_ci case WSA881X_SDM_PDM9_LSB: 46462306a36Sopenharmony_ci case WSA881X_SDM_PDM9_MSB: 46562306a36Sopenharmony_ci case WSA881X_CDC_RX_CTL: 46662306a36Sopenharmony_ci case WSA881X_DEM_BYPASS_DATA0: 46762306a36Sopenharmony_ci case WSA881X_DEM_BYPASS_DATA1: 46862306a36Sopenharmony_ci case WSA881X_DEM_BYPASS_DATA2: 46962306a36Sopenharmony_ci case WSA881X_DEM_BYPASS_DATA3: 47062306a36Sopenharmony_ci case WSA881X_OTP_CTRL0: 47162306a36Sopenharmony_ci case WSA881X_OTP_CTRL1: 47262306a36Sopenharmony_ci case WSA881X_HDRIVE_CTL_GROUP1: 47362306a36Sopenharmony_ci case WSA881X_INTR_MODE: 47462306a36Sopenharmony_ci case WSA881X_INTR_MASK: 47562306a36Sopenharmony_ci case WSA881X_INTR_STATUS: 47662306a36Sopenharmony_ci case WSA881X_INTR_CLEAR: 47762306a36Sopenharmony_ci case WSA881X_INTR_LEVEL: 47862306a36Sopenharmony_ci case WSA881X_INTR_SET: 47962306a36Sopenharmony_ci case WSA881X_INTR_TEST: 48062306a36Sopenharmony_ci case WSA881X_PDM_TEST_MODE: 48162306a36Sopenharmony_ci case WSA881X_ATE_TEST_MODE: 48262306a36Sopenharmony_ci case WSA881X_PIN_CTL_MODE: 48362306a36Sopenharmony_ci case WSA881X_PIN_CTL_OE: 48462306a36Sopenharmony_ci case WSA881X_PIN_WDATA_IOPAD: 48562306a36Sopenharmony_ci case WSA881X_PIN_STATUS: 48662306a36Sopenharmony_ci case WSA881X_DIG_DEBUG_MODE: 48762306a36Sopenharmony_ci case WSA881X_DIG_DEBUG_SEL: 48862306a36Sopenharmony_ci case WSA881X_DIG_DEBUG_EN: 48962306a36Sopenharmony_ci case WSA881X_SWR_HM_TEST1: 49062306a36Sopenharmony_ci case WSA881X_SWR_HM_TEST2: 49162306a36Sopenharmony_ci case WSA881X_TEMP_DETECT_DBG_CTL: 49262306a36Sopenharmony_ci case WSA881X_TEMP_DEBUG_MSB: 49362306a36Sopenharmony_ci case WSA881X_TEMP_DEBUG_LSB: 49462306a36Sopenharmony_ci case WSA881X_SAMPLE_EDGE_SEL: 49562306a36Sopenharmony_ci case WSA881X_IOPAD_CTL: 49662306a36Sopenharmony_ci case WSA881X_SPARE_0: 49762306a36Sopenharmony_ci case WSA881X_SPARE_1: 49862306a36Sopenharmony_ci case WSA881X_SPARE_2: 49962306a36Sopenharmony_ci case WSA881X_OTP_REG_0: 50062306a36Sopenharmony_ci case WSA881X_OTP_REG_1: 50162306a36Sopenharmony_ci case WSA881X_OTP_REG_2: 50262306a36Sopenharmony_ci case WSA881X_OTP_REG_3: 50362306a36Sopenharmony_ci case WSA881X_OTP_REG_4: 50462306a36Sopenharmony_ci case WSA881X_OTP_REG_5: 50562306a36Sopenharmony_ci case WSA881X_OTP_REG_6: 50662306a36Sopenharmony_ci case WSA881X_OTP_REG_7: 50762306a36Sopenharmony_ci case WSA881X_OTP_REG_8: 50862306a36Sopenharmony_ci case WSA881X_OTP_REG_9: 50962306a36Sopenharmony_ci case WSA881X_OTP_REG_10: 51062306a36Sopenharmony_ci case WSA881X_OTP_REG_11: 51162306a36Sopenharmony_ci case WSA881X_OTP_REG_12: 51262306a36Sopenharmony_ci case WSA881X_OTP_REG_13: 51362306a36Sopenharmony_ci case WSA881X_OTP_REG_14: 51462306a36Sopenharmony_ci case WSA881X_OTP_REG_15: 51562306a36Sopenharmony_ci case WSA881X_OTP_REG_16: 51662306a36Sopenharmony_ci case WSA881X_OTP_REG_17: 51762306a36Sopenharmony_ci case WSA881X_OTP_REG_18: 51862306a36Sopenharmony_ci case WSA881X_OTP_REG_19: 51962306a36Sopenharmony_ci case WSA881X_OTP_REG_20: 52062306a36Sopenharmony_ci case WSA881X_OTP_REG_21: 52162306a36Sopenharmony_ci case WSA881X_OTP_REG_22: 52262306a36Sopenharmony_ci case WSA881X_OTP_REG_23: 52362306a36Sopenharmony_ci case WSA881X_OTP_REG_24: 52462306a36Sopenharmony_ci case WSA881X_OTP_REG_25: 52562306a36Sopenharmony_ci case WSA881X_OTP_REG_26: 52662306a36Sopenharmony_ci case WSA881X_OTP_REG_27: 52762306a36Sopenharmony_ci case WSA881X_OTP_REG_28: 52862306a36Sopenharmony_ci case WSA881X_OTP_REG_29: 52962306a36Sopenharmony_ci case WSA881X_OTP_REG_30: 53062306a36Sopenharmony_ci case WSA881X_OTP_REG_31: 53162306a36Sopenharmony_ci case WSA881X_OTP_REG_63: 53262306a36Sopenharmony_ci case WSA881X_BIAS_REF_CTRL: 53362306a36Sopenharmony_ci case WSA881X_BIAS_TEST: 53462306a36Sopenharmony_ci case WSA881X_BIAS_BIAS: 53562306a36Sopenharmony_ci case WSA881X_TEMP_OP: 53662306a36Sopenharmony_ci case WSA881X_TEMP_IREF_CTRL: 53762306a36Sopenharmony_ci case WSA881X_TEMP_ISENS_CTRL: 53862306a36Sopenharmony_ci case WSA881X_TEMP_CLK_CTRL: 53962306a36Sopenharmony_ci case WSA881X_TEMP_TEST: 54062306a36Sopenharmony_ci case WSA881X_TEMP_BIAS: 54162306a36Sopenharmony_ci case WSA881X_TEMP_ADC_CTRL: 54262306a36Sopenharmony_ci case WSA881X_TEMP_DOUT_MSB: 54362306a36Sopenharmony_ci case WSA881X_TEMP_DOUT_LSB: 54462306a36Sopenharmony_ci case WSA881X_ADC_EN_MODU_V: 54562306a36Sopenharmony_ci case WSA881X_ADC_EN_MODU_I: 54662306a36Sopenharmony_ci case WSA881X_ADC_EN_DET_TEST_V: 54762306a36Sopenharmony_ci case WSA881X_ADC_EN_DET_TEST_I: 54862306a36Sopenharmony_ci case WSA881X_ADC_SEL_IBIAS: 54962306a36Sopenharmony_ci case WSA881X_ADC_EN_SEL_IBAIS: 55062306a36Sopenharmony_ci case WSA881X_SPKR_DRV_EN: 55162306a36Sopenharmony_ci case WSA881X_SPKR_DRV_GAIN: 55262306a36Sopenharmony_ci case WSA881X_SPKR_DAC_CTL: 55362306a36Sopenharmony_ci case WSA881X_SPKR_DRV_DBG: 55462306a36Sopenharmony_ci case WSA881X_SPKR_PWRSTG_DBG: 55562306a36Sopenharmony_ci case WSA881X_SPKR_OCP_CTL: 55662306a36Sopenharmony_ci case WSA881X_SPKR_CLIP_CTL: 55762306a36Sopenharmony_ci case WSA881X_SPKR_BBM_CTL: 55862306a36Sopenharmony_ci case WSA881X_SPKR_MISC_CTL1: 55962306a36Sopenharmony_ci case WSA881X_SPKR_MISC_CTL2: 56062306a36Sopenharmony_ci case WSA881X_SPKR_BIAS_INT: 56162306a36Sopenharmony_ci case WSA881X_SPKR_PA_INT: 56262306a36Sopenharmony_ci case WSA881X_SPKR_BIAS_CAL: 56362306a36Sopenharmony_ci case WSA881X_SPKR_BIAS_PSRR: 56462306a36Sopenharmony_ci case WSA881X_SPKR_STATUS1: 56562306a36Sopenharmony_ci case WSA881X_SPKR_STATUS2: 56662306a36Sopenharmony_ci case WSA881X_BOOST_EN_CTL: 56762306a36Sopenharmony_ci case WSA881X_BOOST_CURRENT_LIMIT: 56862306a36Sopenharmony_ci case WSA881X_BOOST_PS_CTL: 56962306a36Sopenharmony_ci case WSA881X_BOOST_PRESET_OUT1: 57062306a36Sopenharmony_ci case WSA881X_BOOST_PRESET_OUT2: 57162306a36Sopenharmony_ci case WSA881X_BOOST_FORCE_OUT: 57262306a36Sopenharmony_ci case WSA881X_BOOST_LDO_PROG: 57362306a36Sopenharmony_ci case WSA881X_BOOST_SLOPE_COMP_ISENSE_FB: 57462306a36Sopenharmony_ci case WSA881X_BOOST_RON_CTL: 57562306a36Sopenharmony_ci case WSA881X_BOOST_LOOP_STABILITY: 57662306a36Sopenharmony_ci case WSA881X_BOOST_ZX_CTL: 57762306a36Sopenharmony_ci case WSA881X_BOOST_START_CTL: 57862306a36Sopenharmony_ci case WSA881X_BOOST_MISC1_CTL: 57962306a36Sopenharmony_ci case WSA881X_BOOST_MISC2_CTL: 58062306a36Sopenharmony_ci case WSA881X_BOOST_MISC3_CTL: 58162306a36Sopenharmony_ci case WSA881X_BOOST_ATEST_CTL: 58262306a36Sopenharmony_ci case WSA881X_SPKR_PROT_FE_GAIN: 58362306a36Sopenharmony_ci case WSA881X_SPKR_PROT_FE_CM_LDO_SET: 58462306a36Sopenharmony_ci case WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET1: 58562306a36Sopenharmony_ci case WSA881X_SPKR_PROT_FE_ISENSE_BIAS_SET2: 58662306a36Sopenharmony_ci case WSA881X_SPKR_PROT_ATEST1: 58762306a36Sopenharmony_ci case WSA881X_SPKR_PROT_ATEST2: 58862306a36Sopenharmony_ci case WSA881X_SPKR_PROT_FE_VSENSE_VCM: 58962306a36Sopenharmony_ci case WSA881X_SPKR_PROT_FE_VSENSE_BIAS_SET1: 59062306a36Sopenharmony_ci case WSA881X_BONGO_RESRV_REG1: 59162306a36Sopenharmony_ci case WSA881X_BONGO_RESRV_REG2: 59262306a36Sopenharmony_ci case WSA881X_SPKR_PROT_SAR: 59362306a36Sopenharmony_ci case WSA881X_SPKR_STATUS3: 59462306a36Sopenharmony_ci return true; 59562306a36Sopenharmony_ci default: 59662306a36Sopenharmony_ci return false; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic bool wsa881x_volatile_register(struct device *dev, unsigned int reg) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci switch (reg) { 60362306a36Sopenharmony_ci case WSA881X_CHIP_ID0: 60462306a36Sopenharmony_ci case WSA881X_CHIP_ID1: 60562306a36Sopenharmony_ci case WSA881X_CHIP_ID2: 60662306a36Sopenharmony_ci case WSA881X_CHIP_ID3: 60762306a36Sopenharmony_ci case WSA881X_BUS_ID: 60862306a36Sopenharmony_ci case WSA881X_TEMP_MSB: 60962306a36Sopenharmony_ci case WSA881X_TEMP_LSB: 61062306a36Sopenharmony_ci case WSA881X_SDM_PDM9_LSB: 61162306a36Sopenharmony_ci case WSA881X_SDM_PDM9_MSB: 61262306a36Sopenharmony_ci case WSA881X_OTP_CTRL1: 61362306a36Sopenharmony_ci case WSA881X_INTR_STATUS: 61462306a36Sopenharmony_ci case WSA881X_ATE_TEST_MODE: 61562306a36Sopenharmony_ci case WSA881X_PIN_STATUS: 61662306a36Sopenharmony_ci case WSA881X_SWR_HM_TEST2: 61762306a36Sopenharmony_ci case WSA881X_SPKR_STATUS1: 61862306a36Sopenharmony_ci case WSA881X_SPKR_STATUS2: 61962306a36Sopenharmony_ci case WSA881X_SPKR_STATUS3: 62062306a36Sopenharmony_ci case WSA881X_OTP_REG_0: 62162306a36Sopenharmony_ci case WSA881X_OTP_REG_1: 62262306a36Sopenharmony_ci case WSA881X_OTP_REG_2: 62362306a36Sopenharmony_ci case WSA881X_OTP_REG_3: 62462306a36Sopenharmony_ci case WSA881X_OTP_REG_4: 62562306a36Sopenharmony_ci case WSA881X_OTP_REG_5: 62662306a36Sopenharmony_ci case WSA881X_OTP_REG_31: 62762306a36Sopenharmony_ci case WSA881X_TEMP_DOUT_MSB: 62862306a36Sopenharmony_ci case WSA881X_TEMP_DOUT_LSB: 62962306a36Sopenharmony_ci case WSA881X_TEMP_OP: 63062306a36Sopenharmony_ci case WSA881X_SPKR_PROT_SAR: 63162306a36Sopenharmony_ci return true; 63262306a36Sopenharmony_ci default: 63362306a36Sopenharmony_ci return false; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_cistatic struct regmap_config wsa881x_regmap_config = { 63862306a36Sopenharmony_ci .reg_bits = 32, 63962306a36Sopenharmony_ci .val_bits = 8, 64062306a36Sopenharmony_ci .cache_type = REGCACHE_MAPLE, 64162306a36Sopenharmony_ci .reg_defaults = wsa881x_defaults, 64262306a36Sopenharmony_ci .max_register = WSA881X_SPKR_STATUS3, 64362306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(wsa881x_defaults), 64462306a36Sopenharmony_ci .volatile_reg = wsa881x_volatile_register, 64562306a36Sopenharmony_ci .readable_reg = wsa881x_readable_register, 64662306a36Sopenharmony_ci .reg_format_endian = REGMAP_ENDIAN_NATIVE, 64762306a36Sopenharmony_ci .val_format_endian = REGMAP_ENDIAN_NATIVE, 64862306a36Sopenharmony_ci}; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cienum { 65162306a36Sopenharmony_ci G_18DB = 0, 65262306a36Sopenharmony_ci G_16P5DB, 65362306a36Sopenharmony_ci G_15DB, 65462306a36Sopenharmony_ci G_13P5DB, 65562306a36Sopenharmony_ci G_12DB, 65662306a36Sopenharmony_ci G_10P5DB, 65762306a36Sopenharmony_ci G_9DB, 65862306a36Sopenharmony_ci G_7P5DB, 65962306a36Sopenharmony_ci G_6DB, 66062306a36Sopenharmony_ci G_4P5DB, 66162306a36Sopenharmony_ci G_3DB, 66262306a36Sopenharmony_ci G_1P5DB, 66362306a36Sopenharmony_ci G_0DB, 66462306a36Sopenharmony_ci}; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci/* 66762306a36Sopenharmony_ci * Private data Structure for wsa881x. All parameters related to 66862306a36Sopenharmony_ci * WSA881X codec needs to be defined here. 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_cistruct wsa881x_priv { 67162306a36Sopenharmony_ci struct regmap *regmap; 67262306a36Sopenharmony_ci struct device *dev; 67362306a36Sopenharmony_ci struct sdw_slave *slave; 67462306a36Sopenharmony_ci struct sdw_stream_config sconfig; 67562306a36Sopenharmony_ci struct sdw_stream_runtime *sruntime; 67662306a36Sopenharmony_ci struct sdw_port_config port_config[WSA881X_MAX_SWR_PORTS]; 67762306a36Sopenharmony_ci struct gpio_desc *sd_n; 67862306a36Sopenharmony_ci /* 67962306a36Sopenharmony_ci * Logical state for SD_N GPIO: high for shutdown, low for enable. 68062306a36Sopenharmony_ci * For backwards compatibility. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci unsigned int sd_n_val; 68362306a36Sopenharmony_ci int version; 68462306a36Sopenharmony_ci int active_ports; 68562306a36Sopenharmony_ci bool port_prepared[WSA881X_MAX_SWR_PORTS]; 68662306a36Sopenharmony_ci bool port_enable[WSA881X_MAX_SWR_PORTS]; 68762306a36Sopenharmony_ci}; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic void wsa881x_init(struct wsa881x_priv *wsa881x) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct regmap *rm = wsa881x->regmap; 69262306a36Sopenharmony_ci unsigned int val = 0; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci regmap_read(rm, WSA881X_CHIP_ID1, &wsa881x->version); 69562306a36Sopenharmony_ci regmap_register_patch(wsa881x->regmap, wsa881x_rev_2_0, 69662306a36Sopenharmony_ci ARRAY_SIZE(wsa881x_rev_2_0)); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* Enable software reset output from soundwire slave */ 69962306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SWR_RESET_EN, 0x07, 0x07); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* Bring out of analog reset */ 70262306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_CDC_RST_CTL, 0x02, 0x02); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* Bring out of digital reset */ 70562306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_CDC_RST_CTL, 0x01, 0x01); 70662306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_CLOCK_CONFIG, 0x10, 0x10); 70762306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SPKR_OCP_CTL, 0x02, 0x02); 70862306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SPKR_MISC_CTL1, 0xC0, 0x80); 70962306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SPKR_MISC_CTL1, 0x06, 0x06); 71062306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SPKR_BIAS_INT, 0xFF, 0x00); 71162306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SPKR_PA_INT, 0xF0, 0x40); 71262306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SPKR_PA_INT, 0x0E, 0x0E); 71362306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BOOST_LOOP_STABILITY, 0x03, 0x03); 71462306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BOOST_MISC2_CTL, 0xFF, 0x14); 71562306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BOOST_START_CTL, 0x80, 0x80); 71662306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BOOST_START_CTL, 0x03, 0x00); 71762306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x0C, 0x04); 71862306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BOOST_SLOPE_COMP_ISENSE_FB, 0x03, 0x00); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci regmap_read(rm, WSA881X_OTP_REG_0, &val); 72162306a36Sopenharmony_ci if (val) 72262306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BOOST_PRESET_OUT1, 0xF0, 0x70); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BOOST_PRESET_OUT2, 0xF0, 0x30); 72562306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SPKR_DRV_EN, 0x08, 0x08); 72662306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BOOST_CURRENT_LIMIT, 0x0F, 0x08); 72762306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SPKR_OCP_CTL, 0x30, 0x30); 72862306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_SPKR_OCP_CTL, 0x0C, 0x00); 72962306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_OTP_REG_28, 0x3F, 0x3A); 73062306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG1, 0xFF, 0xB2); 73162306a36Sopenharmony_ci regmap_update_bits(rm, WSA881X_BONGO_RESRV_REG2, 0xFF, 0x05); 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic int wsa881x_component_probe(struct snd_soc_component *comp) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(comp); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci snd_soc_component_init_regmap(comp, wsa881x->regmap); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return 0; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic int wsa881x_put_pa_gain(struct snd_kcontrol *kc, 74462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct snd_soc_component *comp = snd_soc_kcontrol_component(kc); 74762306a36Sopenharmony_ci struct soc_mixer_control *mc = 74862306a36Sopenharmony_ci (struct soc_mixer_control *)kc->private_value; 74962306a36Sopenharmony_ci int max = mc->max; 75062306a36Sopenharmony_ci unsigned int mask = (1 << fls(max)) - 1; 75162306a36Sopenharmony_ci int val, ret, min_gain, max_gain; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(comp->dev); 75462306a36Sopenharmony_ci if (ret < 0 && ret != -EACCES) 75562306a36Sopenharmony_ci return ret; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci max_gain = (max - ucontrol->value.integer.value[0]) & mask; 75862306a36Sopenharmony_ci /* 75962306a36Sopenharmony_ci * Gain has to set incrementally in 4 steps 76062306a36Sopenharmony_ci * as per HW sequence 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_ci if (max_gain > G_4P5DB) 76362306a36Sopenharmony_ci min_gain = G_0DB; 76462306a36Sopenharmony_ci else 76562306a36Sopenharmony_ci min_gain = max_gain + 3; 76662306a36Sopenharmony_ci /* 76762306a36Sopenharmony_ci * 1ms delay is needed before change in gain 76862306a36Sopenharmony_ci * as per HW requirement. 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_ci usleep_range(1000, 1010); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci for (val = min_gain; max_gain <= val; val--) { 77362306a36Sopenharmony_ci ret = snd_soc_component_update_bits(comp, 77462306a36Sopenharmony_ci WSA881X_SPKR_DRV_GAIN, 77562306a36Sopenharmony_ci WSA881X_SPKR_PAG_GAIN_MASK, 77662306a36Sopenharmony_ci val << 4); 77762306a36Sopenharmony_ci if (ret < 0) 77862306a36Sopenharmony_ci dev_err(comp->dev, "Failed to change PA gain"); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci usleep_range(1000, 1010); 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci pm_runtime_mark_last_busy(comp->dev); 78462306a36Sopenharmony_ci pm_runtime_put_autosuspend(comp->dev); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return 1; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int wsa881x_get_port(struct snd_kcontrol *kcontrol, 79062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 79362306a36Sopenharmony_ci struct wsa881x_priv *data = snd_soc_component_get_drvdata(comp); 79462306a36Sopenharmony_ci struct soc_mixer_control *mixer = 79562306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 79662306a36Sopenharmony_ci int portidx = mixer->reg; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = data->port_enable[portidx]; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic int wsa881x_boost_ctrl(struct snd_soc_component *comp, bool enable) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci if (enable) 80762306a36Sopenharmony_ci snd_soc_component_update_bits(comp, WSA881X_BOOST_EN_CTL, 80862306a36Sopenharmony_ci WSA881X_BOOST_EN_MASK, 80962306a36Sopenharmony_ci WSA881X_BOOST_EN); 81062306a36Sopenharmony_ci else 81162306a36Sopenharmony_ci snd_soc_component_update_bits(comp, WSA881X_BOOST_EN_CTL, 81262306a36Sopenharmony_ci WSA881X_BOOST_EN_MASK, 0); 81362306a36Sopenharmony_ci /* 81462306a36Sopenharmony_ci * 1.5ms sleep is needed after boost enable/disable as per 81562306a36Sopenharmony_ci * HW requirement 81662306a36Sopenharmony_ci */ 81762306a36Sopenharmony_ci usleep_range(1500, 1510); 81862306a36Sopenharmony_ci return 0; 81962306a36Sopenharmony_ci} 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic int wsa881x_set_port(struct snd_kcontrol *kcontrol, 82262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 82562306a36Sopenharmony_ci struct wsa881x_priv *data = snd_soc_component_get_drvdata(comp); 82662306a36Sopenharmony_ci struct soc_mixer_control *mixer = 82762306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 82862306a36Sopenharmony_ci int portidx = mixer->reg; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) { 83162306a36Sopenharmony_ci if (data->port_enable[portidx]) 83262306a36Sopenharmony_ci return 0; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci data->port_enable[portidx] = true; 83562306a36Sopenharmony_ci } else { 83662306a36Sopenharmony_ci if (!data->port_enable[portidx]) 83762306a36Sopenharmony_ci return 0; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci data->port_enable[portidx] = false; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (portidx == WSA881X_PORT_BOOST) /* Boost Switch */ 84362306a36Sopenharmony_ci wsa881x_boost_ctrl(comp, data->port_enable[portidx]); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci return 1; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic const char * const smart_boost_lvl_text[] = { 84962306a36Sopenharmony_ci "6.625 V", "6.750 V", "6.875 V", "7.000 V", 85062306a36Sopenharmony_ci "7.125 V", "7.250 V", "7.375 V", "7.500 V", 85162306a36Sopenharmony_ci "7.625 V", "7.750 V", "7.875 V", "8.000 V", 85262306a36Sopenharmony_ci "8.125 V", "8.250 V", "8.375 V", "8.500 V" 85362306a36Sopenharmony_ci}; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic const struct soc_enum smart_boost_lvl_enum = 85662306a36Sopenharmony_ci SOC_ENUM_SINGLE(WSA881X_BOOST_PRESET_OUT1, 0, 85762306a36Sopenharmony_ci ARRAY_SIZE(smart_boost_lvl_text), 85862306a36Sopenharmony_ci smart_boost_lvl_text); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(pa_gain, 0, 150, 0); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_cistatic const struct snd_kcontrol_new wsa881x_snd_controls[] = { 86362306a36Sopenharmony_ci SOC_ENUM("Smart Boost Level", smart_boost_lvl_enum), 86462306a36Sopenharmony_ci WSA881X_PA_GAIN_TLV("PA Volume", WSA881X_SPKR_DRV_GAIN, 86562306a36Sopenharmony_ci 4, 0xC, 1, pa_gain), 86662306a36Sopenharmony_ci SOC_SINGLE_EXT("DAC Switch", WSA881X_PORT_DAC, 0, 1, 0, 86762306a36Sopenharmony_ci wsa881x_get_port, wsa881x_set_port), 86862306a36Sopenharmony_ci SOC_SINGLE_EXT("COMP Switch", WSA881X_PORT_COMP, 0, 1, 0, 86962306a36Sopenharmony_ci wsa881x_get_port, wsa881x_set_port), 87062306a36Sopenharmony_ci SOC_SINGLE_EXT("BOOST Switch", WSA881X_PORT_BOOST, 0, 1, 0, 87162306a36Sopenharmony_ci wsa881x_get_port, wsa881x_set_port), 87262306a36Sopenharmony_ci SOC_SINGLE_EXT("VISENSE Switch", WSA881X_PORT_VISENSE, 0, 1, 0, 87362306a36Sopenharmony_ci wsa881x_get_port, wsa881x_set_port), 87462306a36Sopenharmony_ci}; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic const struct snd_soc_dapm_route wsa881x_audio_map[] = { 87762306a36Sopenharmony_ci { "RDAC", NULL, "IN" }, 87862306a36Sopenharmony_ci { "RDAC", NULL, "DCLK" }, 87962306a36Sopenharmony_ci { "RDAC", NULL, "ACLK" }, 88062306a36Sopenharmony_ci { "RDAC", NULL, "Bandgap" }, 88162306a36Sopenharmony_ci { "SPKR PGA", NULL, "RDAC" }, 88262306a36Sopenharmony_ci { "SPKR", NULL, "SPKR PGA" }, 88362306a36Sopenharmony_ci}; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic int wsa881x_visense_txfe_ctrl(struct snd_soc_component *comp, 88662306a36Sopenharmony_ci bool enable) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(comp); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (enable) { 89162306a36Sopenharmony_ci regmap_multi_reg_write(wsa881x->regmap, wsa881x_vi_txfe_en_2_0, 89262306a36Sopenharmony_ci ARRAY_SIZE(wsa881x_vi_txfe_en_2_0)); 89362306a36Sopenharmony_ci } else { 89462306a36Sopenharmony_ci snd_soc_component_update_bits(comp, 89562306a36Sopenharmony_ci WSA881X_SPKR_PROT_FE_VSENSE_VCM, 89662306a36Sopenharmony_ci 0x08, 0x08); 89762306a36Sopenharmony_ci /* 89862306a36Sopenharmony_ci * 200us sleep is needed after visense txfe disable as per 89962306a36Sopenharmony_ci * HW requirement. 90062306a36Sopenharmony_ci */ 90162306a36Sopenharmony_ci usleep_range(200, 210); 90262306a36Sopenharmony_ci snd_soc_component_update_bits(comp, WSA881X_SPKR_PROT_FE_GAIN, 90362306a36Sopenharmony_ci 0x01, 0x00); 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci return 0; 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic int wsa881x_visense_adc_ctrl(struct snd_soc_component *comp, 90962306a36Sopenharmony_ci bool enable) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci snd_soc_component_update_bits(comp, WSA881X_ADC_EN_MODU_V, BIT(7), 91262306a36Sopenharmony_ci (enable << 7)); 91362306a36Sopenharmony_ci snd_soc_component_update_bits(comp, WSA881X_ADC_EN_MODU_I, BIT(7), 91462306a36Sopenharmony_ci (enable << 7)); 91562306a36Sopenharmony_ci return 0; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistatic int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w, 91962306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm); 92262306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(comp); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci switch (event) { 92562306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 92662306a36Sopenharmony_ci snd_soc_component_update_bits(comp, WSA881X_SPKR_OCP_CTL, 92762306a36Sopenharmony_ci WSA881X_SPKR_OCP_MASK, 92862306a36Sopenharmony_ci WSA881X_SPKR_OCP_EN); 92962306a36Sopenharmony_ci regmap_multi_reg_write(wsa881x->regmap, wsa881x_pre_pmu_pa_2_0, 93062306a36Sopenharmony_ci ARRAY_SIZE(wsa881x_pre_pmu_pa_2_0)); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci snd_soc_component_update_bits(comp, WSA881X_SPKR_DRV_GAIN, 93362306a36Sopenharmony_ci WSA881X_PA_GAIN_SEL_MASK, 93462306a36Sopenharmony_ci WSA881X_PA_GAIN_SEL_REG); 93562306a36Sopenharmony_ci break; 93662306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 93762306a36Sopenharmony_ci if (wsa881x->port_prepared[WSA881X_PORT_VISENSE]) { 93862306a36Sopenharmony_ci wsa881x_visense_txfe_ctrl(comp, true); 93962306a36Sopenharmony_ci snd_soc_component_update_bits(comp, 94062306a36Sopenharmony_ci WSA881X_ADC_EN_SEL_IBAIS, 94162306a36Sopenharmony_ci 0x07, 0x01); 94262306a36Sopenharmony_ci wsa881x_visense_adc_ctrl(comp, true); 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMD: 94762306a36Sopenharmony_ci if (wsa881x->port_prepared[WSA881X_PORT_VISENSE]) { 94862306a36Sopenharmony_ci wsa881x_visense_adc_ctrl(comp, false); 94962306a36Sopenharmony_ci wsa881x_visense_txfe_ctrl(comp, false); 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci snd_soc_component_update_bits(comp, WSA881X_SPKR_OCP_CTL, 95362306a36Sopenharmony_ci WSA881X_SPKR_OCP_MASK, 95462306a36Sopenharmony_ci WSA881X_SPKR_OCP_EN | 95562306a36Sopenharmony_ci WSA881X_SPKR_OCP_HOLD); 95662306a36Sopenharmony_ci break; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci return 0; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget wsa881x_dapm_widgets[] = { 96262306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("IN"), 96362306a36Sopenharmony_ci SND_SOC_DAPM_DAC_E("RDAC", NULL, WSA881X_SPKR_DAC_CTL, 7, 0, 96462306a36Sopenharmony_ci NULL, 96562306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 96662306a36Sopenharmony_ci SND_SOC_DAPM_PGA_E("SPKR PGA", SND_SOC_NOPM, 0, 0, NULL, 0, 96762306a36Sopenharmony_ci wsa881x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU | 96862306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), 96962306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("DCLK", WSA881X_CDC_DIG_CLK_CTL, 0, 0, NULL, 97062306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 97162306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("ACLK", WSA881X_CDC_ANA_CLK_CTL, 0, 0, NULL, 97262306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 97362306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("Bandgap", WSA881X_TEMP_OP, 3, 0, 97462306a36Sopenharmony_ci NULL, 97562306a36Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 97662306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("SPKR"), 97762306a36Sopenharmony_ci}; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic int wsa881x_hw_params(struct snd_pcm_substream *substream, 98062306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 98162306a36Sopenharmony_ci struct snd_soc_dai *dai) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = dev_get_drvdata(dai->dev); 98462306a36Sopenharmony_ci int i; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci wsa881x->active_ports = 0; 98762306a36Sopenharmony_ci for (i = 0; i < WSA881X_MAX_SWR_PORTS; i++) { 98862306a36Sopenharmony_ci if (!wsa881x->port_enable[i]) 98962306a36Sopenharmony_ci continue; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci wsa881x->port_config[wsa881x->active_ports] = 99262306a36Sopenharmony_ci wsa881x_pconfig[i]; 99362306a36Sopenharmony_ci wsa881x->active_ports++; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return sdw_stream_add_slave(wsa881x->slave, &wsa881x->sconfig, 99762306a36Sopenharmony_ci wsa881x->port_config, wsa881x->active_ports, 99862306a36Sopenharmony_ci wsa881x->sruntime); 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic int wsa881x_hw_free(struct snd_pcm_substream *substream, 100262306a36Sopenharmony_ci struct snd_soc_dai *dai) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = dev_get_drvdata(dai->dev); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci sdw_stream_remove_slave(wsa881x->slave, wsa881x->sruntime); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci return 0; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic int wsa881x_set_sdw_stream(struct snd_soc_dai *dai, 101262306a36Sopenharmony_ci void *stream, int direction) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = dev_get_drvdata(dai->dev); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci wsa881x->sruntime = stream; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci return 0; 101962306a36Sopenharmony_ci} 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic int wsa881x_digital_mute(struct snd_soc_dai *dai, int mute, int stream) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = dev_get_drvdata(dai->dev); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci if (mute) 102662306a36Sopenharmony_ci regmap_update_bits(wsa881x->regmap, WSA881X_SPKR_DRV_EN, 0x80, 102762306a36Sopenharmony_ci 0x00); 102862306a36Sopenharmony_ci else 102962306a36Sopenharmony_ci regmap_update_bits(wsa881x->regmap, WSA881X_SPKR_DRV_EN, 0x80, 103062306a36Sopenharmony_ci 0x80); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci return 0; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic const struct snd_soc_dai_ops wsa881x_dai_ops = { 103662306a36Sopenharmony_ci .hw_params = wsa881x_hw_params, 103762306a36Sopenharmony_ci .hw_free = wsa881x_hw_free, 103862306a36Sopenharmony_ci .mute_stream = wsa881x_digital_mute, 103962306a36Sopenharmony_ci .set_stream = wsa881x_set_sdw_stream, 104062306a36Sopenharmony_ci}; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic struct snd_soc_dai_driver wsa881x_dais[] = { 104362306a36Sopenharmony_ci { 104462306a36Sopenharmony_ci .name = "SPKR", 104562306a36Sopenharmony_ci .id = 0, 104662306a36Sopenharmony_ci .playback = { 104762306a36Sopenharmony_ci .stream_name = "SPKR Playback", 104862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 104962306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 105062306a36Sopenharmony_ci .rate_max = 48000, 105162306a36Sopenharmony_ci .rate_min = 48000, 105262306a36Sopenharmony_ci .channels_min = 1, 105362306a36Sopenharmony_ci .channels_max = 1, 105462306a36Sopenharmony_ci }, 105562306a36Sopenharmony_ci .ops = &wsa881x_dai_ops, 105662306a36Sopenharmony_ci }, 105762306a36Sopenharmony_ci}; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic const struct snd_soc_component_driver wsa881x_component_drv = { 106062306a36Sopenharmony_ci .name = "WSA881x", 106162306a36Sopenharmony_ci .probe = wsa881x_component_probe, 106262306a36Sopenharmony_ci .controls = wsa881x_snd_controls, 106362306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(wsa881x_snd_controls), 106462306a36Sopenharmony_ci .dapm_widgets = wsa881x_dapm_widgets, 106562306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets), 106662306a36Sopenharmony_ci .dapm_routes = wsa881x_audio_map, 106762306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map), 106862306a36Sopenharmony_ci .endianness = 1, 106962306a36Sopenharmony_ci}; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_cistatic int wsa881x_update_status(struct sdw_slave *slave, 107262306a36Sopenharmony_ci enum sdw_slave_status status) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = dev_get_drvdata(&slave->dev); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (status == SDW_SLAVE_ATTACHED && slave->dev_num > 0) 107762306a36Sopenharmony_ci wsa881x_init(wsa881x); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci return 0; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic int wsa881x_port_prep(struct sdw_slave *slave, 108362306a36Sopenharmony_ci struct sdw_prepare_ch *prepare_ch, 108462306a36Sopenharmony_ci enum sdw_port_prep_ops state) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = dev_get_drvdata(&slave->dev); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci if (state == SDW_OPS_PORT_POST_PREP) 108962306a36Sopenharmony_ci wsa881x->port_prepared[prepare_ch->num - 1] = true; 109062306a36Sopenharmony_ci else 109162306a36Sopenharmony_ci wsa881x->port_prepared[prepare_ch->num - 1] = false; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci return 0; 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic int wsa881x_bus_config(struct sdw_slave *slave, 109762306a36Sopenharmony_ci struct sdw_bus_params *params) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank), 110062306a36Sopenharmony_ci 0x01); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return 0; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic const struct sdw_slave_ops wsa881x_slave_ops = { 110662306a36Sopenharmony_ci .update_status = wsa881x_update_status, 110762306a36Sopenharmony_ci .bus_config = wsa881x_bus_config, 110862306a36Sopenharmony_ci .port_prep = wsa881x_port_prep, 110962306a36Sopenharmony_ci}; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_cistatic int wsa881x_probe(struct sdw_slave *pdev, 111262306a36Sopenharmony_ci const struct sdw_device_id *id) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci struct wsa881x_priv *wsa881x; 111562306a36Sopenharmony_ci struct device *dev = &pdev->dev; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci wsa881x = devm_kzalloc(dev, sizeof(*wsa881x), GFP_KERNEL); 111862306a36Sopenharmony_ci if (!wsa881x) 111962306a36Sopenharmony_ci return -ENOMEM; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", 112262306a36Sopenharmony_ci GPIOD_FLAGS_BIT_NONEXCLUSIVE); 112362306a36Sopenharmony_ci if (IS_ERR(wsa881x->sd_n)) 112462306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(wsa881x->sd_n), 112562306a36Sopenharmony_ci "Shutdown Control GPIO not found\n"); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci /* 112862306a36Sopenharmony_ci * Backwards compatibility work-around. 112962306a36Sopenharmony_ci * 113062306a36Sopenharmony_ci * The SD_N GPIO is active low, however upstream DTS used always active 113162306a36Sopenharmony_ci * high. Changing the flag in driver and DTS will break backwards 113262306a36Sopenharmony_ci * compatibility, so add a simple value inversion to work with both old 113362306a36Sopenharmony_ci * and new DTS. 113462306a36Sopenharmony_ci * 113562306a36Sopenharmony_ci * This won't work properly with DTS using the flags properly in cases: 113662306a36Sopenharmony_ci * 1. Old DTS with proper ACTIVE_LOW, however such case was broken 113762306a36Sopenharmony_ci * before as the driver required the active high. 113862306a36Sopenharmony_ci * 2. New DTS with proper ACTIVE_HIGH (intended), which is rare case 113962306a36Sopenharmony_ci * (not existing upstream) but possible. This is the price of 114062306a36Sopenharmony_ci * backwards compatibility, therefore this hack should be removed at 114162306a36Sopenharmony_ci * some point. 114262306a36Sopenharmony_ci */ 114362306a36Sopenharmony_ci wsa881x->sd_n_val = gpiod_is_active_low(wsa881x->sd_n); 114462306a36Sopenharmony_ci if (!wsa881x->sd_n_val) 114562306a36Sopenharmony_ci dev_warn(dev, "Using ACTIVE_HIGH for shutdown GPIO. Your DTB might be outdated or you use unsupported configuration for the GPIO."); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci dev_set_drvdata(dev, wsa881x); 114862306a36Sopenharmony_ci wsa881x->slave = pdev; 114962306a36Sopenharmony_ci wsa881x->dev = dev; 115062306a36Sopenharmony_ci wsa881x->sconfig.ch_count = 1; 115162306a36Sopenharmony_ci wsa881x->sconfig.bps = 1; 115262306a36Sopenharmony_ci wsa881x->sconfig.frame_rate = 48000; 115362306a36Sopenharmony_ci wsa881x->sconfig.direction = SDW_DATA_DIR_RX; 115462306a36Sopenharmony_ci wsa881x->sconfig.type = SDW_STREAM_PDM; 115562306a36Sopenharmony_ci pdev->prop.sink_ports = GENMASK(WSA881X_MAX_SWR_PORTS, 0); 115662306a36Sopenharmony_ci pdev->prop.sink_dpn_prop = wsa_sink_dpn_prop; 115762306a36Sopenharmony_ci pdev->prop.scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; 115862306a36Sopenharmony_ci gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci wsa881x->regmap = devm_regmap_init_sdw(pdev, &wsa881x_regmap_config); 116162306a36Sopenharmony_ci if (IS_ERR(wsa881x->regmap)) 116262306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(wsa881x->regmap), "regmap_init failed\n"); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 3000); 116562306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 116662306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 116762306a36Sopenharmony_ci pm_runtime_set_active(dev); 116862306a36Sopenharmony_ci pm_runtime_enable(dev); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci return devm_snd_soc_register_component(dev, 117162306a36Sopenharmony_ci &wsa881x_component_drv, 117262306a36Sopenharmony_ci wsa881x_dais, 117362306a36Sopenharmony_ci ARRAY_SIZE(wsa881x_dais)); 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic int __maybe_unused wsa881x_runtime_suspend(struct device *dev) 117762306a36Sopenharmony_ci{ 117862306a36Sopenharmony_ci struct regmap *regmap = dev_get_regmap(dev, NULL); 117962306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = dev_get_drvdata(dev); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci gpiod_direction_output(wsa881x->sd_n, wsa881x->sd_n_val); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci regcache_cache_only(regmap, true); 118462306a36Sopenharmony_ci regcache_mark_dirty(regmap); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci return 0; 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_cistatic int __maybe_unused wsa881x_runtime_resume(struct device *dev) 119062306a36Sopenharmony_ci{ 119162306a36Sopenharmony_ci struct sdw_slave *slave = dev_to_sdw_dev(dev); 119262306a36Sopenharmony_ci struct regmap *regmap = dev_get_regmap(dev, NULL); 119362306a36Sopenharmony_ci struct wsa881x_priv *wsa881x = dev_get_drvdata(dev); 119462306a36Sopenharmony_ci unsigned long time; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci gpiod_direction_output(wsa881x->sd_n, !wsa881x->sd_n_val); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci time = wait_for_completion_timeout(&slave->initialization_complete, 119962306a36Sopenharmony_ci msecs_to_jiffies(WSA881X_PROBE_TIMEOUT)); 120062306a36Sopenharmony_ci if (!time) { 120162306a36Sopenharmony_ci dev_err(dev, "Initialization not complete, timed out\n"); 120262306a36Sopenharmony_ci gpiod_direction_output(wsa881x->sd_n, wsa881x->sd_n_val); 120362306a36Sopenharmony_ci return -ETIMEDOUT; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci regcache_cache_only(regmap, false); 120762306a36Sopenharmony_ci regcache_sync(regmap); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci return 0; 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_cistatic const struct dev_pm_ops wsa881x_pm_ops = { 121362306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(wsa881x_runtime_suspend, wsa881x_runtime_resume, NULL) 121462306a36Sopenharmony_ci}; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_cistatic const struct sdw_device_id wsa881x_slave_id[] = { 121762306a36Sopenharmony_ci SDW_SLAVE_ENTRY(0x0217, 0x2010, 0), 121862306a36Sopenharmony_ci SDW_SLAVE_ENTRY(0x0217, 0x2110, 0), 121962306a36Sopenharmony_ci {}, 122062306a36Sopenharmony_ci}; 122162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(sdw, wsa881x_slave_id); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic struct sdw_driver wsa881x_codec_driver = { 122462306a36Sopenharmony_ci .probe = wsa881x_probe, 122562306a36Sopenharmony_ci .ops = &wsa881x_slave_ops, 122662306a36Sopenharmony_ci .id_table = wsa881x_slave_id, 122762306a36Sopenharmony_ci .driver = { 122862306a36Sopenharmony_ci .name = "wsa881x-codec", 122962306a36Sopenharmony_ci .pm = &wsa881x_pm_ops, 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci}; 123262306a36Sopenharmony_cimodule_sdw_driver(wsa881x_codec_driver); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ciMODULE_DESCRIPTION("WSA881x codec driver"); 123562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1236