162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * CS42L43 core driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2022-2023 Cirrus Logic, Inc. and 662306a36Sopenharmony_ci * Cirrus Logic International Semiconductor Ltd. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/bitops.h> 1062306a36Sopenharmony_ci#include <linux/build_bug.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/firmware.h> 1562306a36Sopenharmony_ci#include <linux/jiffies.h> 1662306a36Sopenharmony_ci#include <linux/mfd/core.h> 1762306a36Sopenharmony_ci#include <linux/mfd/cs42l43-regs.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2062306a36Sopenharmony_ci#include <linux/soundwire/sdw.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "cs42l43.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define CS42L43_RESET_DELAY 20 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define CS42L43_SDW_ATTACH_TIMEOUT 500 2762306a36Sopenharmony_ci#define CS42L43_SDW_DETACH_TIMEOUT 100 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define CS42L43_MCU_BOOT_STAGE1 1 3062306a36Sopenharmony_ci#define CS42L43_MCU_BOOT_STAGE2 2 3162306a36Sopenharmony_ci#define CS42L43_MCU_BOOT_STAGE3 3 3262306a36Sopenharmony_ci#define CS42L43_MCU_BOOT_STAGE4 4 3362306a36Sopenharmony_ci#define CS42L43_MCU_POLL 5000 3462306a36Sopenharmony_ci#define CS42L43_MCU_CMD_TIMEOUT 20000 3562306a36Sopenharmony_ci#define CS42L43_MCU_UPDATE_FORMAT 3 3662306a36Sopenharmony_ci#define CS42L43_MCU_UPDATE_OFFSET 0x100000 3762306a36Sopenharmony_ci#define CS42L43_MCU_UPDATE_TIMEOUT 500000 3862306a36Sopenharmony_ci#define CS42L43_MCU_UPDATE_RETRIES 5 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define CS42L43_MCU_SUPPORTED_REV 0x2105 4162306a36Sopenharmony_ci#define CS42L43_MCU_SHADOW_REGS_REQUIRED_REV 0x2200 4262306a36Sopenharmony_ci#define CS42L43_MCU_SUPPORTED_BIOS_REV 0x0001 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define CS42L43_VDDP_DELAY 50 4562306a36Sopenharmony_ci#define CS42L43_VDDD_DELAY 1000 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define CS42L43_AUTOSUSPEND_TIME 250 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct cs42l43_patch_header { 5062306a36Sopenharmony_ci __le16 version; 5162306a36Sopenharmony_ci __le16 size; 5262306a36Sopenharmony_ci u8 reserved; 5362306a36Sopenharmony_ci u8 secure; 5462306a36Sopenharmony_ci __le16 bss_size; 5562306a36Sopenharmony_ci __le32 apply_addr; 5662306a36Sopenharmony_ci __le32 checksum; 5762306a36Sopenharmony_ci __le32 sha; 5862306a36Sopenharmony_ci __le16 swrev; 5962306a36Sopenharmony_ci __le16 patchid; 6062306a36Sopenharmony_ci __le16 ipxid; 6162306a36Sopenharmony_ci __le16 romver; 6262306a36Sopenharmony_ci __le32 load_addr; 6362306a36Sopenharmony_ci} __packed; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic const struct reg_sequence cs42l43_reva_patch[] = { 6662306a36Sopenharmony_ci { 0x4000, 0x00000055 }, 6762306a36Sopenharmony_ci { 0x4000, 0x000000AA }, 6862306a36Sopenharmony_ci { 0x10084, 0x00000000 }, 6962306a36Sopenharmony_ci { 0x1741C, 0x00CD2000 }, 7062306a36Sopenharmony_ci { 0x1718C, 0x00000003 }, 7162306a36Sopenharmony_ci { 0x4000, 0x00000000 }, 7262306a36Sopenharmony_ci { CS42L43_CCM_BLK_CLK_CONTROL, 0x00000002 }, 7362306a36Sopenharmony_ci { CS42L43_HPPATHVOL, 0x011B011B }, 7462306a36Sopenharmony_ci { CS42L43_OSC_DIV_SEL, 0x00000001 }, 7562306a36Sopenharmony_ci { CS42L43_DACCNFG2, 0x00000005 }, 7662306a36Sopenharmony_ci { CS42L43_MIC_DETECT_CONTROL_ANDROID, 0x80790079 }, 7762306a36Sopenharmony_ci { CS42L43_RELID, 0x0000000F }, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciconst struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { 8162306a36Sopenharmony_ci { CS42L43_DRV_CTRL1, 0x000186C0 }, 8262306a36Sopenharmony_ci { CS42L43_DRV_CTRL3, 0x286DB018 }, 8362306a36Sopenharmony_ci { CS42L43_DRV_CTRL4, 0x000006D8 }, 8462306a36Sopenharmony_ci { CS42L43_DRV_CTRL_5, 0x136C00C0 }, 8562306a36Sopenharmony_ci { CS42L43_GPIO_CTRL1, 0x00000707 }, 8662306a36Sopenharmony_ci { CS42L43_GPIO_CTRL2, 0x00000000 }, 8762306a36Sopenharmony_ci { CS42L43_GPIO_FN_SEL, 0x00000004 }, 8862306a36Sopenharmony_ci { CS42L43_MCLK_SRC_SEL, 0x00000000 }, 8962306a36Sopenharmony_ci { CS42L43_SAMPLE_RATE1, 0x00000003 }, 9062306a36Sopenharmony_ci { CS42L43_SAMPLE_RATE2, 0x00000003 }, 9162306a36Sopenharmony_ci { CS42L43_SAMPLE_RATE3, 0x00000003 }, 9262306a36Sopenharmony_ci { CS42L43_SAMPLE_RATE4, 0x00000003 }, 9362306a36Sopenharmony_ci { CS42L43_PLL_CONTROL, 0x00000000 }, 9462306a36Sopenharmony_ci { CS42L43_FS_SELECT1, 0x00000000 }, 9562306a36Sopenharmony_ci { CS42L43_FS_SELECT2, 0x00000000 }, 9662306a36Sopenharmony_ci { CS42L43_FS_SELECT3, 0x00000000 }, 9762306a36Sopenharmony_ci { CS42L43_FS_SELECT4, 0x00000000 }, 9862306a36Sopenharmony_ci { CS42L43_PDM_CONTROL, 0x00000000 }, 9962306a36Sopenharmony_ci { CS42L43_ASP_CLK_CONFIG1, 0x00010001 }, 10062306a36Sopenharmony_ci { CS42L43_ASP_CLK_CONFIG2, 0x00000000 }, 10162306a36Sopenharmony_ci { CS42L43_OSC_DIV_SEL, 0x00000001 }, 10262306a36Sopenharmony_ci { CS42L43_ADC_B_CTRL1, 0x00000000 }, 10362306a36Sopenharmony_ci { CS42L43_ADC_B_CTRL2, 0x00000000 }, 10462306a36Sopenharmony_ci { CS42L43_DECIM_HPF_WNF_CTRL1, 0x00000001 }, 10562306a36Sopenharmony_ci { CS42L43_DECIM_HPF_WNF_CTRL2, 0x00000001 }, 10662306a36Sopenharmony_ci { CS42L43_DECIM_HPF_WNF_CTRL3, 0x00000001 }, 10762306a36Sopenharmony_ci { CS42L43_DECIM_HPF_WNF_CTRL4, 0x00000001 }, 10862306a36Sopenharmony_ci { CS42L43_DMIC_PDM_CTRL, 0x00000000 }, 10962306a36Sopenharmony_ci { CS42L43_DECIM_VOL_CTRL_CH1_CH2, 0x20122012 }, 11062306a36Sopenharmony_ci { CS42L43_DECIM_VOL_CTRL_CH3_CH4, 0x20122012 }, 11162306a36Sopenharmony_ci { CS42L43_INTP_VOLUME_CTRL1, 0x00000180 }, 11262306a36Sopenharmony_ci { CS42L43_INTP_VOLUME_CTRL2, 0x00000180 }, 11362306a36Sopenharmony_ci { CS42L43_AMP1_2_VOL_RAMP, 0x00000022 }, 11462306a36Sopenharmony_ci { CS42L43_ASP_CTRL, 0x00000004 }, 11562306a36Sopenharmony_ci { CS42L43_ASP_FSYNC_CTRL1, 0x000000FA }, 11662306a36Sopenharmony_ci { CS42L43_ASP_FSYNC_CTRL2, 0x00000001 }, 11762306a36Sopenharmony_ci { CS42L43_ASP_FSYNC_CTRL3, 0x00000000 }, 11862306a36Sopenharmony_ci { CS42L43_ASP_FSYNC_CTRL4, 0x000001F4 }, 11962306a36Sopenharmony_ci { CS42L43_ASP_DATA_CTRL, 0x0000003A }, 12062306a36Sopenharmony_ci { CS42L43_ASP_RX_EN, 0x00000000 }, 12162306a36Sopenharmony_ci { CS42L43_ASP_TX_EN, 0x00000000 }, 12262306a36Sopenharmony_ci { CS42L43_ASP_RX_CH1_CTRL, 0x00170001 }, 12362306a36Sopenharmony_ci { CS42L43_ASP_RX_CH2_CTRL, 0x00170031 }, 12462306a36Sopenharmony_ci { CS42L43_ASP_RX_CH3_CTRL, 0x00170061 }, 12562306a36Sopenharmony_ci { CS42L43_ASP_RX_CH4_CTRL, 0x00170091 }, 12662306a36Sopenharmony_ci { CS42L43_ASP_RX_CH5_CTRL, 0x001700C1 }, 12762306a36Sopenharmony_ci { CS42L43_ASP_RX_CH6_CTRL, 0x001700F1 }, 12862306a36Sopenharmony_ci { CS42L43_ASP_TX_CH1_CTRL, 0x00170001 }, 12962306a36Sopenharmony_ci { CS42L43_ASP_TX_CH2_CTRL, 0x00170031 }, 13062306a36Sopenharmony_ci { CS42L43_ASP_TX_CH3_CTRL, 0x00170061 }, 13162306a36Sopenharmony_ci { CS42L43_ASP_TX_CH4_CTRL, 0x00170091 }, 13262306a36Sopenharmony_ci { CS42L43_ASP_TX_CH5_CTRL, 0x001700C1 }, 13362306a36Sopenharmony_ci { CS42L43_ASP_TX_CH6_CTRL, 0x001700F1 }, 13462306a36Sopenharmony_ci { CS42L43_ASPTX1_INPUT, 0x00000000 }, 13562306a36Sopenharmony_ci { CS42L43_ASPTX2_INPUT, 0x00000000 }, 13662306a36Sopenharmony_ci { CS42L43_ASPTX3_INPUT, 0x00000000 }, 13762306a36Sopenharmony_ci { CS42L43_ASPTX4_INPUT, 0x00000000 }, 13862306a36Sopenharmony_ci { CS42L43_ASPTX5_INPUT, 0x00000000 }, 13962306a36Sopenharmony_ci { CS42L43_ASPTX6_INPUT, 0x00000000 }, 14062306a36Sopenharmony_ci { CS42L43_SWIRE_DP1_CH1_INPUT, 0x00000000 }, 14162306a36Sopenharmony_ci { CS42L43_SWIRE_DP1_CH2_INPUT, 0x00000000 }, 14262306a36Sopenharmony_ci { CS42L43_SWIRE_DP1_CH3_INPUT, 0x00000000 }, 14362306a36Sopenharmony_ci { CS42L43_SWIRE_DP1_CH4_INPUT, 0x00000000 }, 14462306a36Sopenharmony_ci { CS42L43_SWIRE_DP2_CH1_INPUT, 0x00000000 }, 14562306a36Sopenharmony_ci { CS42L43_SWIRE_DP2_CH2_INPUT, 0x00000000 }, 14662306a36Sopenharmony_ci { CS42L43_SWIRE_DP3_CH1_INPUT, 0x00000000 }, 14762306a36Sopenharmony_ci { CS42L43_SWIRE_DP3_CH2_INPUT, 0x00000000 }, 14862306a36Sopenharmony_ci { CS42L43_SWIRE_DP4_CH1_INPUT, 0x00000000 }, 14962306a36Sopenharmony_ci { CS42L43_SWIRE_DP4_CH2_INPUT, 0x00000000 }, 15062306a36Sopenharmony_ci { CS42L43_ASRC_INT1_INPUT1, 0x00000000 }, 15162306a36Sopenharmony_ci { CS42L43_ASRC_INT2_INPUT1, 0x00000000 }, 15262306a36Sopenharmony_ci { CS42L43_ASRC_INT3_INPUT1, 0x00000000 }, 15362306a36Sopenharmony_ci { CS42L43_ASRC_INT4_INPUT1, 0x00000000 }, 15462306a36Sopenharmony_ci { CS42L43_ASRC_DEC1_INPUT1, 0x00000000 }, 15562306a36Sopenharmony_ci { CS42L43_ASRC_DEC2_INPUT1, 0x00000000 }, 15662306a36Sopenharmony_ci { CS42L43_ASRC_DEC3_INPUT1, 0x00000000 }, 15762306a36Sopenharmony_ci { CS42L43_ASRC_DEC4_INPUT1, 0x00000000 }, 15862306a36Sopenharmony_ci { CS42L43_ISRC1INT1_INPUT1, 0x00000000 }, 15962306a36Sopenharmony_ci { CS42L43_ISRC1INT2_INPUT1, 0x00000000 }, 16062306a36Sopenharmony_ci { CS42L43_ISRC1DEC1_INPUT1, 0x00000000 }, 16162306a36Sopenharmony_ci { CS42L43_ISRC1DEC2_INPUT1, 0x00000000 }, 16262306a36Sopenharmony_ci { CS42L43_ISRC2INT1_INPUT1, 0x00000000 }, 16362306a36Sopenharmony_ci { CS42L43_ISRC2INT2_INPUT1, 0x00000000 }, 16462306a36Sopenharmony_ci { CS42L43_ISRC2DEC1_INPUT1, 0x00000000 }, 16562306a36Sopenharmony_ci { CS42L43_ISRC2DEC2_INPUT1, 0x00000000 }, 16662306a36Sopenharmony_ci { CS42L43_EQ1MIX_INPUT1, 0x00800000 }, 16762306a36Sopenharmony_ci { CS42L43_EQ1MIX_INPUT2, 0x00800000 }, 16862306a36Sopenharmony_ci { CS42L43_EQ1MIX_INPUT3, 0x00800000 }, 16962306a36Sopenharmony_ci { CS42L43_EQ1MIX_INPUT4, 0x00800000 }, 17062306a36Sopenharmony_ci { CS42L43_EQ2MIX_INPUT1, 0x00800000 }, 17162306a36Sopenharmony_ci { CS42L43_EQ2MIX_INPUT2, 0x00800000 }, 17262306a36Sopenharmony_ci { CS42L43_EQ2MIX_INPUT3, 0x00800000 }, 17362306a36Sopenharmony_ci { CS42L43_EQ2MIX_INPUT4, 0x00800000 }, 17462306a36Sopenharmony_ci { CS42L43_SPDIF1_INPUT1, 0x00000000 }, 17562306a36Sopenharmony_ci { CS42L43_SPDIF2_INPUT1, 0x00000000 }, 17662306a36Sopenharmony_ci { CS42L43_AMP1MIX_INPUT1, 0x00800000 }, 17762306a36Sopenharmony_ci { CS42L43_AMP1MIX_INPUT2, 0x00800000 }, 17862306a36Sopenharmony_ci { CS42L43_AMP1MIX_INPUT3, 0x00800000 }, 17962306a36Sopenharmony_ci { CS42L43_AMP1MIX_INPUT4, 0x00800000 }, 18062306a36Sopenharmony_ci { CS42L43_AMP2MIX_INPUT1, 0x00800000 }, 18162306a36Sopenharmony_ci { CS42L43_AMP2MIX_INPUT2, 0x00800000 }, 18262306a36Sopenharmony_ci { CS42L43_AMP2MIX_INPUT3, 0x00800000 }, 18362306a36Sopenharmony_ci { CS42L43_AMP2MIX_INPUT4, 0x00800000 }, 18462306a36Sopenharmony_ci { CS42L43_AMP3MIX_INPUT1, 0x00800000 }, 18562306a36Sopenharmony_ci { CS42L43_AMP3MIX_INPUT2, 0x00800000 }, 18662306a36Sopenharmony_ci { CS42L43_AMP3MIX_INPUT3, 0x00800000 }, 18762306a36Sopenharmony_ci { CS42L43_AMP3MIX_INPUT4, 0x00800000 }, 18862306a36Sopenharmony_ci { CS42L43_AMP4MIX_INPUT1, 0x00800000 }, 18962306a36Sopenharmony_ci { CS42L43_AMP4MIX_INPUT2, 0x00800000 }, 19062306a36Sopenharmony_ci { CS42L43_AMP4MIX_INPUT3, 0x00800000 }, 19162306a36Sopenharmony_ci { CS42L43_AMP4MIX_INPUT4, 0x00800000 }, 19262306a36Sopenharmony_ci { CS42L43_ASRC_INT_ENABLES, 0x00000100 }, 19362306a36Sopenharmony_ci { CS42L43_ASRC_DEC_ENABLES, 0x00000100 }, 19462306a36Sopenharmony_ci { CS42L43_PDNCNTL, 0x00000000 }, 19562306a36Sopenharmony_ci { CS42L43_RINGSENSE_DEB_CTRL, 0x0000001B }, 19662306a36Sopenharmony_ci { CS42L43_TIPSENSE_DEB_CTRL, 0x0000001B }, 19762306a36Sopenharmony_ci { CS42L43_HS2, 0x050106F3 }, 19862306a36Sopenharmony_ci { CS42L43_STEREO_MIC_CTRL, 0x00000000 }, 19962306a36Sopenharmony_ci { CS42L43_STEREO_MIC_CLAMP_CTRL, 0x00000001 }, 20062306a36Sopenharmony_ci { CS42L43_BLOCK_EN2, 0x00000000 }, 20162306a36Sopenharmony_ci { CS42L43_BLOCK_EN3, 0x00000000 }, 20262306a36Sopenharmony_ci { CS42L43_BLOCK_EN4, 0x00000000 }, 20362306a36Sopenharmony_ci { CS42L43_BLOCK_EN5, 0x00000000 }, 20462306a36Sopenharmony_ci { CS42L43_BLOCK_EN6, 0x00000000 }, 20562306a36Sopenharmony_ci { CS42L43_BLOCK_EN7, 0x00000000 }, 20662306a36Sopenharmony_ci { CS42L43_BLOCK_EN8, 0x00000000 }, 20762306a36Sopenharmony_ci { CS42L43_BLOCK_EN9, 0x00000000 }, 20862306a36Sopenharmony_ci { CS42L43_BLOCK_EN10, 0x00000000 }, 20962306a36Sopenharmony_ci { CS42L43_BLOCK_EN11, 0x00000000 }, 21062306a36Sopenharmony_ci { CS42L43_TONE_CH1_CTRL, 0x00000000 }, 21162306a36Sopenharmony_ci { CS42L43_TONE_CH2_CTRL, 0x00000000 }, 21262306a36Sopenharmony_ci { CS42L43_MIC_DETECT_CONTROL_1, 0x00000003 }, 21362306a36Sopenharmony_ci { CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL, 0x02000003 }, 21462306a36Sopenharmony_ci { CS42L43_MIC_DETECT_CONTROL_ANDROID, 0x80790079 }, 21562306a36Sopenharmony_ci { CS42L43_ISRC1_CTRL, 0x00000000 }, 21662306a36Sopenharmony_ci { CS42L43_ISRC2_CTRL, 0x00000000 }, 21762306a36Sopenharmony_ci { CS42L43_CTRL_REG, 0x00000006 }, 21862306a36Sopenharmony_ci { CS42L43_FDIV_FRAC, 0x40000000 }, 21962306a36Sopenharmony_ci { CS42L43_CAL_RATIO, 0x00000080 }, 22062306a36Sopenharmony_ci { CS42L43_SPI_CLK_CONFIG1, 0x00000001 }, 22162306a36Sopenharmony_ci { CS42L43_SPI_CONFIG1, 0x00000000 }, 22262306a36Sopenharmony_ci { CS42L43_SPI_CONFIG2, 0x00000000 }, 22362306a36Sopenharmony_ci { CS42L43_SPI_CONFIG3, 0x00000001 }, 22462306a36Sopenharmony_ci { CS42L43_SPI_CONFIG4, 0x00000000 }, 22562306a36Sopenharmony_ci { CS42L43_TRAN_CONFIG3, 0x00000000 }, 22662306a36Sopenharmony_ci { CS42L43_TRAN_CONFIG4, 0x00000000 }, 22762306a36Sopenharmony_ci { CS42L43_TRAN_CONFIG5, 0x00000000 }, 22862306a36Sopenharmony_ci { CS42L43_TRAN_CONFIG6, 0x00000000 }, 22962306a36Sopenharmony_ci { CS42L43_TRAN_CONFIG7, 0x00000000 }, 23062306a36Sopenharmony_ci { CS42L43_TRAN_CONFIG8, 0x00000000 }, 23162306a36Sopenharmony_ci { CS42L43_DACCNFG1, 0x00000008 }, 23262306a36Sopenharmony_ci { CS42L43_DACCNFG2, 0x00000005 }, 23362306a36Sopenharmony_ci { CS42L43_HPPATHVOL, 0x011B011B }, 23462306a36Sopenharmony_ci { CS42L43_PGAVOL, 0x00003470 }, 23562306a36Sopenharmony_ci { CS42L43_LOADDETENA, 0x00000000 }, 23662306a36Sopenharmony_ci { CS42L43_CTRL, 0x00000037 }, 23762306a36Sopenharmony_ci { CS42L43_COEFF_DATA_IN0, 0x00000000 }, 23862306a36Sopenharmony_ci { CS42L43_COEFF_RD_WR0, 0x00000000 }, 23962306a36Sopenharmony_ci { CS42L43_START_EQZ0, 0x00000000 }, 24062306a36Sopenharmony_ci { CS42L43_MUTE_EQ_IN0, 0x00000000 }, 24162306a36Sopenharmony_ci { CS42L43_DECIM_MASK, 0x0000000F }, 24262306a36Sopenharmony_ci { CS42L43_EQ_MIX_MASK, 0x0000000F }, 24362306a36Sopenharmony_ci { CS42L43_ASP_MASK, 0x000000FF }, 24462306a36Sopenharmony_ci { CS42L43_PLL_MASK, 0x00000003 }, 24562306a36Sopenharmony_ci { CS42L43_SOFT_MASK, 0x0000FFFF }, 24662306a36Sopenharmony_ci { CS42L43_SWIRE_MASK, 0x00007FFF }, 24762306a36Sopenharmony_ci { CS42L43_MSM_MASK, 0x00000FFF }, 24862306a36Sopenharmony_ci { CS42L43_ACC_DET_MASK, 0x00000FFF }, 24962306a36Sopenharmony_ci { CS42L43_I2C_TGT_MASK, 0x00000003 }, 25062306a36Sopenharmony_ci { CS42L43_SPI_MSTR_MASK, 0x00000007 }, 25162306a36Sopenharmony_ci { CS42L43_SW_TO_SPI_BRIDGE_MASK, 0x00000001 }, 25262306a36Sopenharmony_ci { CS42L43_OTP_MASK, 0x00000007 }, 25362306a36Sopenharmony_ci { CS42L43_CLASS_D_AMP_MASK, 0x00003FFF }, 25462306a36Sopenharmony_ci { CS42L43_GPIO_INT_MASK, 0x0000003F }, 25562306a36Sopenharmony_ci { CS42L43_ASRC_MASK, 0x0000000F }, 25662306a36Sopenharmony_ci { CS42L43_HPOUT_MASK, 0x00000003 }, 25762306a36Sopenharmony_ci}; 25862306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, MFD_CS42L43); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cibool cs42l43_readable_register(struct device *dev, unsigned int reg) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci switch (reg) { 26362306a36Sopenharmony_ci case CS42L43_DEVID: 26462306a36Sopenharmony_ci case CS42L43_REVID: 26562306a36Sopenharmony_ci case CS42L43_RELID: 26662306a36Sopenharmony_ci case CS42L43_SFT_RESET: 26762306a36Sopenharmony_ci case CS42L43_DRV_CTRL1: 26862306a36Sopenharmony_ci case CS42L43_DRV_CTRL3: 26962306a36Sopenharmony_ci case CS42L43_DRV_CTRL4: 27062306a36Sopenharmony_ci case CS42L43_DRV_CTRL_5: 27162306a36Sopenharmony_ci case CS42L43_GPIO_CTRL1: 27262306a36Sopenharmony_ci case CS42L43_GPIO_CTRL2: 27362306a36Sopenharmony_ci case CS42L43_GPIO_STS: 27462306a36Sopenharmony_ci case CS42L43_GPIO_FN_SEL: 27562306a36Sopenharmony_ci case CS42L43_MCLK_SRC_SEL: 27662306a36Sopenharmony_ci case CS42L43_SAMPLE_RATE1 ... CS42L43_SAMPLE_RATE4: 27762306a36Sopenharmony_ci case CS42L43_PLL_CONTROL: 27862306a36Sopenharmony_ci case CS42L43_FS_SELECT1 ... CS42L43_FS_SELECT4: 27962306a36Sopenharmony_ci case CS42L43_PDM_CONTROL: 28062306a36Sopenharmony_ci case CS42L43_ASP_CLK_CONFIG1 ... CS42L43_ASP_CLK_CONFIG2: 28162306a36Sopenharmony_ci case CS42L43_OSC_DIV_SEL: 28262306a36Sopenharmony_ci case CS42L43_ADC_B_CTRL1 ... CS42L43_ADC_B_CTRL2: 28362306a36Sopenharmony_ci case CS42L43_DECIM_HPF_WNF_CTRL1 ... CS42L43_DECIM_HPF_WNF_CTRL4: 28462306a36Sopenharmony_ci case CS42L43_DMIC_PDM_CTRL: 28562306a36Sopenharmony_ci case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4: 28662306a36Sopenharmony_ci case CS42L43_INTP_VOLUME_CTRL1 ... CS42L43_INTP_VOLUME_CTRL2: 28762306a36Sopenharmony_ci case CS42L43_AMP1_2_VOL_RAMP: 28862306a36Sopenharmony_ci case CS42L43_ASP_CTRL: 28962306a36Sopenharmony_ci case CS42L43_ASP_FSYNC_CTRL1 ... CS42L43_ASP_FSYNC_CTRL4: 29062306a36Sopenharmony_ci case CS42L43_ASP_DATA_CTRL: 29162306a36Sopenharmony_ci case CS42L43_ASP_RX_EN ... CS42L43_ASP_TX_EN: 29262306a36Sopenharmony_ci case CS42L43_ASP_RX_CH1_CTRL ... CS42L43_ASP_RX_CH6_CTRL: 29362306a36Sopenharmony_ci case CS42L43_ASP_TX_CH1_CTRL ... CS42L43_ASP_TX_CH6_CTRL: 29462306a36Sopenharmony_ci case CS42L43_OTP_REVISION_ID: 29562306a36Sopenharmony_ci case CS42L43_ASPTX1_INPUT: 29662306a36Sopenharmony_ci case CS42L43_ASPTX2_INPUT: 29762306a36Sopenharmony_ci case CS42L43_ASPTX3_INPUT: 29862306a36Sopenharmony_ci case CS42L43_ASPTX4_INPUT: 29962306a36Sopenharmony_ci case CS42L43_ASPTX5_INPUT: 30062306a36Sopenharmony_ci case CS42L43_ASPTX6_INPUT: 30162306a36Sopenharmony_ci case CS42L43_SWIRE_DP1_CH1_INPUT: 30262306a36Sopenharmony_ci case CS42L43_SWIRE_DP1_CH2_INPUT: 30362306a36Sopenharmony_ci case CS42L43_SWIRE_DP1_CH3_INPUT: 30462306a36Sopenharmony_ci case CS42L43_SWIRE_DP1_CH4_INPUT: 30562306a36Sopenharmony_ci case CS42L43_SWIRE_DP2_CH1_INPUT: 30662306a36Sopenharmony_ci case CS42L43_SWIRE_DP2_CH2_INPUT: 30762306a36Sopenharmony_ci case CS42L43_SWIRE_DP3_CH1_INPUT: 30862306a36Sopenharmony_ci case CS42L43_SWIRE_DP3_CH2_INPUT: 30962306a36Sopenharmony_ci case CS42L43_SWIRE_DP4_CH1_INPUT: 31062306a36Sopenharmony_ci case CS42L43_SWIRE_DP4_CH2_INPUT: 31162306a36Sopenharmony_ci case CS42L43_ASRC_INT1_INPUT1: 31262306a36Sopenharmony_ci case CS42L43_ASRC_INT2_INPUT1: 31362306a36Sopenharmony_ci case CS42L43_ASRC_INT3_INPUT1: 31462306a36Sopenharmony_ci case CS42L43_ASRC_INT4_INPUT1: 31562306a36Sopenharmony_ci case CS42L43_ASRC_DEC1_INPUT1: 31662306a36Sopenharmony_ci case CS42L43_ASRC_DEC2_INPUT1: 31762306a36Sopenharmony_ci case CS42L43_ASRC_DEC3_INPUT1: 31862306a36Sopenharmony_ci case CS42L43_ASRC_DEC4_INPUT1: 31962306a36Sopenharmony_ci case CS42L43_ISRC1INT1_INPUT1: 32062306a36Sopenharmony_ci case CS42L43_ISRC1INT2_INPUT1: 32162306a36Sopenharmony_ci case CS42L43_ISRC1DEC1_INPUT1: 32262306a36Sopenharmony_ci case CS42L43_ISRC1DEC2_INPUT1: 32362306a36Sopenharmony_ci case CS42L43_ISRC2INT1_INPUT1: 32462306a36Sopenharmony_ci case CS42L43_ISRC2INT2_INPUT1: 32562306a36Sopenharmony_ci case CS42L43_ISRC2DEC1_INPUT1: 32662306a36Sopenharmony_ci case CS42L43_ISRC2DEC2_INPUT1: 32762306a36Sopenharmony_ci case CS42L43_EQ1MIX_INPUT1 ... CS42L43_EQ1MIX_INPUT4: 32862306a36Sopenharmony_ci case CS42L43_EQ2MIX_INPUT1 ... CS42L43_EQ2MIX_INPUT4: 32962306a36Sopenharmony_ci case CS42L43_SPDIF1_INPUT1: 33062306a36Sopenharmony_ci case CS42L43_SPDIF2_INPUT1: 33162306a36Sopenharmony_ci case CS42L43_AMP1MIX_INPUT1 ... CS42L43_AMP1MIX_INPUT4: 33262306a36Sopenharmony_ci case CS42L43_AMP2MIX_INPUT1 ... CS42L43_AMP2MIX_INPUT4: 33362306a36Sopenharmony_ci case CS42L43_AMP3MIX_INPUT1 ... CS42L43_AMP3MIX_INPUT4: 33462306a36Sopenharmony_ci case CS42L43_AMP4MIX_INPUT1 ... CS42L43_AMP4MIX_INPUT4: 33562306a36Sopenharmony_ci case CS42L43_ASRC_INT_ENABLES ... CS42L43_ASRC_DEC_ENABLES: 33662306a36Sopenharmony_ci case CS42L43_PDNCNTL: 33762306a36Sopenharmony_ci case CS42L43_RINGSENSE_DEB_CTRL: 33862306a36Sopenharmony_ci case CS42L43_TIPSENSE_DEB_CTRL: 33962306a36Sopenharmony_ci case CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS: 34062306a36Sopenharmony_ci case CS42L43_HS2: 34162306a36Sopenharmony_ci case CS42L43_HS_STAT: 34262306a36Sopenharmony_ci case CS42L43_MCU_SW_INTERRUPT: 34362306a36Sopenharmony_ci case CS42L43_STEREO_MIC_CTRL: 34462306a36Sopenharmony_ci case CS42L43_STEREO_MIC_CLAMP_CTRL: 34562306a36Sopenharmony_ci case CS42L43_BLOCK_EN2 ... CS42L43_BLOCK_EN11: 34662306a36Sopenharmony_ci case CS42L43_TONE_CH1_CTRL ... CS42L43_TONE_CH2_CTRL: 34762306a36Sopenharmony_ci case CS42L43_MIC_DETECT_CONTROL_1: 34862306a36Sopenharmony_ci case CS42L43_DETECT_STATUS_1: 34962306a36Sopenharmony_ci case CS42L43_HS_BIAS_SENSE_AND_CLAMP_AUTOCONTROL: 35062306a36Sopenharmony_ci case CS42L43_MIC_DETECT_CONTROL_ANDROID: 35162306a36Sopenharmony_ci case CS42L43_ISRC1_CTRL: 35262306a36Sopenharmony_ci case CS42L43_ISRC2_CTRL: 35362306a36Sopenharmony_ci case CS42L43_CTRL_REG: 35462306a36Sopenharmony_ci case CS42L43_FDIV_FRAC: 35562306a36Sopenharmony_ci case CS42L43_CAL_RATIO: 35662306a36Sopenharmony_ci case CS42L43_SPI_CLK_CONFIG1: 35762306a36Sopenharmony_ci case CS42L43_SPI_CONFIG1 ... CS42L43_SPI_CONFIG4: 35862306a36Sopenharmony_ci case CS42L43_SPI_STATUS1 ... CS42L43_SPI_STATUS2: 35962306a36Sopenharmony_ci case CS42L43_TRAN_CONFIG1 ... CS42L43_TRAN_CONFIG8: 36062306a36Sopenharmony_ci case CS42L43_TRAN_STATUS1 ... CS42L43_TRAN_STATUS3: 36162306a36Sopenharmony_ci case CS42L43_TX_DATA: 36262306a36Sopenharmony_ci case CS42L43_RX_DATA: 36362306a36Sopenharmony_ci case CS42L43_DACCNFG1 ... CS42L43_DACCNFG2: 36462306a36Sopenharmony_ci case CS42L43_HPPATHVOL: 36562306a36Sopenharmony_ci case CS42L43_PGAVOL: 36662306a36Sopenharmony_ci case CS42L43_LOADDETRESULTS: 36762306a36Sopenharmony_ci case CS42L43_LOADDETENA: 36862306a36Sopenharmony_ci case CS42L43_CTRL: 36962306a36Sopenharmony_ci case CS42L43_COEFF_DATA_IN0: 37062306a36Sopenharmony_ci case CS42L43_COEFF_RD_WR0: 37162306a36Sopenharmony_ci case CS42L43_INIT_DONE0: 37262306a36Sopenharmony_ci case CS42L43_START_EQZ0: 37362306a36Sopenharmony_ci case CS42L43_MUTE_EQ_IN0: 37462306a36Sopenharmony_ci case CS42L43_DECIM_INT ... CS42L43_HPOUT_INT: 37562306a36Sopenharmony_ci case CS42L43_DECIM_MASK ... CS42L43_HPOUT_MASK: 37662306a36Sopenharmony_ci case CS42L43_DECIM_INT_SHADOW ... CS42L43_HP_OUT_SHADOW: 37762306a36Sopenharmony_ci case CS42L43_BOOT_CONTROL: 37862306a36Sopenharmony_ci case CS42L43_BLOCK_EN: 37962306a36Sopenharmony_ci case CS42L43_SHUTTER_CONTROL: 38062306a36Sopenharmony_ci case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX: 38162306a36Sopenharmony_ci return true; 38262306a36Sopenharmony_ci default: 38362306a36Sopenharmony_ci return false; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, MFD_CS42L43); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cibool cs42l43_precious_register(struct device *dev, unsigned int reg) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci switch (reg) { 39162306a36Sopenharmony_ci case CS42L43_SFT_RESET: 39262306a36Sopenharmony_ci case CS42L43_TX_DATA: 39362306a36Sopenharmony_ci case CS42L43_RX_DATA: 39462306a36Sopenharmony_ci case CS42L43_DECIM_INT ... CS42L43_HPOUT_INT: 39562306a36Sopenharmony_ci case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX: 39662306a36Sopenharmony_ci return true; 39762306a36Sopenharmony_ci default: 39862306a36Sopenharmony_ci return false; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, MFD_CS42L43); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cibool cs42l43_volatile_register(struct device *dev, unsigned int reg) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci switch (reg) { 40662306a36Sopenharmony_ci case CS42L43_DEVID: 40762306a36Sopenharmony_ci case CS42L43_REVID: 40862306a36Sopenharmony_ci case CS42L43_RELID: 40962306a36Sopenharmony_ci case CS42L43_GPIO_STS: 41062306a36Sopenharmony_ci case CS42L43_OTP_REVISION_ID: 41162306a36Sopenharmony_ci case CS42L43_TIP_RING_SENSE_INTERRUPT_STATUS: 41262306a36Sopenharmony_ci case CS42L43_HS_STAT: 41362306a36Sopenharmony_ci case CS42L43_MCU_SW_INTERRUPT: 41462306a36Sopenharmony_ci case CS42L43_DETECT_STATUS_1: 41562306a36Sopenharmony_ci case CS42L43_SPI_STATUS1 ... CS42L43_SPI_STATUS2: 41662306a36Sopenharmony_ci case CS42L43_TRAN_CONFIG1 ... CS42L43_TRAN_CONFIG2: 41762306a36Sopenharmony_ci case CS42L43_TRAN_CONFIG8: 41862306a36Sopenharmony_ci case CS42L43_TRAN_STATUS1 ... CS42L43_TRAN_STATUS3: 41962306a36Sopenharmony_ci case CS42L43_LOADDETRESULTS: 42062306a36Sopenharmony_ci case CS42L43_INIT_DONE0: 42162306a36Sopenharmony_ci case CS42L43_DECIM_INT_SHADOW ... CS42L43_HP_OUT_SHADOW: 42262306a36Sopenharmony_ci case CS42L43_BOOT_CONTROL: 42362306a36Sopenharmony_ci case CS42L43_BLOCK_EN: 42462306a36Sopenharmony_ci return true; 42562306a36Sopenharmony_ci default: 42662306a36Sopenharmony_ci return cs42l43_precious_register(dev, reg); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, MFD_CS42L43); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci#define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT) 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci#define CS42L43_IRQ_REG(name, reg) REGMAP_IRQ_REG(CS42L43_##name, \ 43462306a36Sopenharmony_ci CS42L43_IRQ_OFFSET(reg), \ 43562306a36Sopenharmony_ci CS42L43_##name##_INT_MASK) 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const struct regmap_irq cs42l43_regmap_irqs[] = { 43862306a36Sopenharmony_ci CS42L43_IRQ_REG(PLL_LOST_LOCK, PLL), 43962306a36Sopenharmony_ci CS42L43_IRQ_REG(PLL_READY, PLL), 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci CS42L43_IRQ_REG(HP_STARTUP_DONE, MSM), 44262306a36Sopenharmony_ci CS42L43_IRQ_REG(HP_SHUTDOWN_DONE, MSM), 44362306a36Sopenharmony_ci CS42L43_IRQ_REG(HSDET_DONE, MSM), 44462306a36Sopenharmony_ci CS42L43_IRQ_REG(TIPSENSE_UNPLUG_DB, MSM), 44562306a36Sopenharmony_ci CS42L43_IRQ_REG(TIPSENSE_PLUG_DB, MSM), 44662306a36Sopenharmony_ci CS42L43_IRQ_REG(RINGSENSE_UNPLUG_DB, MSM), 44762306a36Sopenharmony_ci CS42L43_IRQ_REG(RINGSENSE_PLUG_DB, MSM), 44862306a36Sopenharmony_ci CS42L43_IRQ_REG(TIPSENSE_UNPLUG_PDET, MSM), 44962306a36Sopenharmony_ci CS42L43_IRQ_REG(TIPSENSE_PLUG_PDET, MSM), 45062306a36Sopenharmony_ci CS42L43_IRQ_REG(RINGSENSE_UNPLUG_PDET, MSM), 45162306a36Sopenharmony_ci CS42L43_IRQ_REG(RINGSENSE_PLUG_PDET, MSM), 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci CS42L43_IRQ_REG(HS2_BIAS_SENSE, ACC_DET), 45462306a36Sopenharmony_ci CS42L43_IRQ_REG(HS1_BIAS_SENSE, ACC_DET), 45562306a36Sopenharmony_ci CS42L43_IRQ_REG(DC_DETECT1_FALSE, ACC_DET), 45662306a36Sopenharmony_ci CS42L43_IRQ_REG(DC_DETECT1_TRUE, ACC_DET), 45762306a36Sopenharmony_ci CS42L43_IRQ_REG(HSBIAS_CLAMPED, ACC_DET), 45862306a36Sopenharmony_ci CS42L43_IRQ_REG(HS3_4_BIAS_SENSE, ACC_DET), 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP2_CLK_STOP_FAULT, CLASS_D_AMP), 46162306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP1_CLK_STOP_FAULT, CLASS_D_AMP), 46262306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP2_VDDSPK_FAULT, CLASS_D_AMP), 46362306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP1_VDDSPK_FAULT, CLASS_D_AMP), 46462306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP2_SHUTDOWN_DONE, CLASS_D_AMP), 46562306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP1_SHUTDOWN_DONE, CLASS_D_AMP), 46662306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP2_STARTUP_DONE, CLASS_D_AMP), 46762306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP1_STARTUP_DONE, CLASS_D_AMP), 46862306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP2_THERM_SHDN, CLASS_D_AMP), 46962306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP1_THERM_SHDN, CLASS_D_AMP), 47062306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP2_THERM_WARN, CLASS_D_AMP), 47162306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP1_THERM_WARN, CLASS_D_AMP), 47262306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP2_SCDET, CLASS_D_AMP), 47362306a36Sopenharmony_ci CS42L43_IRQ_REG(AMP1_SCDET, CLASS_D_AMP), 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci CS42L43_IRQ_REG(GPIO3_FALL, GPIO), 47662306a36Sopenharmony_ci CS42L43_IRQ_REG(GPIO3_RISE, GPIO), 47762306a36Sopenharmony_ci CS42L43_IRQ_REG(GPIO2_FALL, GPIO), 47862306a36Sopenharmony_ci CS42L43_IRQ_REG(GPIO2_RISE, GPIO), 47962306a36Sopenharmony_ci CS42L43_IRQ_REG(GPIO1_FALL, GPIO), 48062306a36Sopenharmony_ci CS42L43_IRQ_REG(GPIO1_RISE, GPIO), 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci CS42L43_IRQ_REG(HP_ILIMIT, HPOUT), 48362306a36Sopenharmony_ci CS42L43_IRQ_REG(HP_LOADDET_DONE, HPOUT), 48462306a36Sopenharmony_ci}; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic const struct regmap_irq_chip cs42l43_irq_chip = { 48762306a36Sopenharmony_ci .name = "cs42l43", 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci .status_base = CS42L43_DECIM_INT, 49062306a36Sopenharmony_ci .mask_base = CS42L43_DECIM_MASK, 49162306a36Sopenharmony_ci .num_regs = 16, 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci .irqs = cs42l43_regmap_irqs, 49462306a36Sopenharmony_ci .num_irqs = ARRAY_SIZE(cs42l43_regmap_irqs), 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci .runtime_pm = true, 49762306a36Sopenharmony_ci}; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic const char * const cs42l43_core_supplies[] = { 50062306a36Sopenharmony_ci "vdd-a", "vdd-io", "vdd-cp", 50162306a36Sopenharmony_ci}; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic const char * const cs42l43_parent_supplies[] = { "vdd-amp" }; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic const struct mfd_cell cs42l43_devs[] = { 50662306a36Sopenharmony_ci { .name = "cs42l43-pinctrl", }, 50762306a36Sopenharmony_ci { .name = "cs42l43-spi", }, 50862306a36Sopenharmony_ci { 50962306a36Sopenharmony_ci .name = "cs42l43-codec", 51062306a36Sopenharmony_ci .parent_supplies = cs42l43_parent_supplies, 51162306a36Sopenharmony_ci .num_parent_supplies = ARRAY_SIZE(cs42l43_parent_supplies), 51262306a36Sopenharmony_ci }, 51362306a36Sopenharmony_ci}; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/* 51662306a36Sopenharmony_ci * If the device is connected over Soundwire, as well as soft resetting the 51762306a36Sopenharmony_ci * device, this function will also way for the device to detach from the bus 51862306a36Sopenharmony_ci * before returning. 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_cistatic int cs42l43_soft_reset(struct cs42l43 *cs42l43) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci static const struct reg_sequence reset[] = { 52362306a36Sopenharmony_ci { CS42L43_SFT_RESET, CS42L43_SFT_RESET_VAL }, 52462306a36Sopenharmony_ci }; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci reinit_completion(&cs42l43->device_detach); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* 52962306a36Sopenharmony_ci * Apply cache only because the soft reset will cause the device to 53062306a36Sopenharmony_ci * detach from the soundwire bus. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci regcache_cache_only(cs42l43->regmap, true); 53362306a36Sopenharmony_ci regmap_multi_reg_write_bypassed(cs42l43->regmap, reset, ARRAY_SIZE(reset)); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci msleep(CS42L43_RESET_DELAY); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (cs42l43->sdw) { 53862306a36Sopenharmony_ci unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_DETACH_TIMEOUT); 53962306a36Sopenharmony_ci unsigned long time; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci time = wait_for_completion_timeout(&cs42l43->device_detach, timeout); 54262306a36Sopenharmony_ci if (!time) { 54362306a36Sopenharmony_ci dev_err(cs42l43->dev, "Timed out waiting for device detach\n"); 54462306a36Sopenharmony_ci return -ETIMEDOUT; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return -EAGAIN; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci/* 55262306a36Sopenharmony_ci * This function is essentially a no-op on I2C, but will wait for the device to 55362306a36Sopenharmony_ci * attach when the device is used on a SoundWire bus. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_cistatic int cs42l43_wait_for_attach(struct cs42l43 *cs42l43) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci if (!cs42l43->attached) { 55862306a36Sopenharmony_ci unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_ATTACH_TIMEOUT); 55962306a36Sopenharmony_ci unsigned long time; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci time = wait_for_completion_timeout(&cs42l43->device_attach, timeout); 56262306a36Sopenharmony_ci if (!time) { 56362306a36Sopenharmony_ci dev_err(cs42l43->dev, "Timed out waiting for device re-attach\n"); 56462306a36Sopenharmony_ci return -ETIMEDOUT; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci regcache_cache_only(cs42l43->regmap, false); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* The hardware requires enabling OSC_DIV before doing any SoundWire reads. */ 57162306a36Sopenharmony_ci if (cs42l43->sdw) 57262306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_OSC_DIV_SEL, 57362306a36Sopenharmony_ci CS42L43_OSC_DIV2_EN_MASK); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return 0; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/* 57962306a36Sopenharmony_ci * This function will advance the firmware into boot stage 3 from boot stage 2. 58062306a36Sopenharmony_ci * Boot stage 3 is required to send commands to the firmware. This is achieved 58162306a36Sopenharmony_ci * by setting the firmware NEED configuration register to zero, this indicates 58262306a36Sopenharmony_ci * no configuration is required forcing the firmware to advance to boot stage 3. 58362306a36Sopenharmony_ci * 58462306a36Sopenharmony_ci * Later revisions of the firmware require the use of an alternative register 58562306a36Sopenharmony_ci * for this purpose, which is indicated through the shadow flag. 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_cistatic int cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci unsigned int need_reg = CS42L43_NEED_CONFIGS; 59062306a36Sopenharmony_ci unsigned int val; 59162306a36Sopenharmony_ci int ret; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (shadow) 59462306a36Sopenharmony_ci need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci regmap_write(cs42l43->regmap, need_reg, 0); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS, 59962306a36Sopenharmony_ci val, (val == CS42L43_MCU_BOOT_STAGE3), 60062306a36Sopenharmony_ci CS42L43_MCU_POLL, CS42L43_MCU_CMD_TIMEOUT); 60162306a36Sopenharmony_ci if (ret) { 60262306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to move to stage 3: %d, 0x%x\n", ret, val); 60362306a36Sopenharmony_ci return ret; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci return -EAGAIN; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/* 61062306a36Sopenharmony_ci * This function will return the firmware to boot stage 2 from boot stage 3. 61162306a36Sopenharmony_ci * Boot stage 2 is required to apply updates to the firmware. This is achieved 61262306a36Sopenharmony_ci * by setting the firmware NEED configuration register to FW_PATCH_NEED_CFG, 61362306a36Sopenharmony_ci * setting the HAVE configuration register to 0, and soft resetting. The 61462306a36Sopenharmony_ci * firmware will see it is missing a patch configuration and will pause in boot 61562306a36Sopenharmony_ci * stage 2. 61662306a36Sopenharmony_ci * 61762306a36Sopenharmony_ci * Note: Unlike cs42l43_mcu_stage_2_3 there is no need to consider the shadow 61862306a36Sopenharmony_ci * register here as the driver will only return to boot stage 2 if the firmware 61962306a36Sopenharmony_ci * requires update which means the revision does not include shadow register 62062306a36Sopenharmony_ci * support. 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_cistatic int cs42l43_mcu_stage_3_2(struct cs42l43 *cs42l43) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_NEED_CONFIGS, 62562306a36Sopenharmony_ci CS42L43_FW_PATCH_NEED_CFG_MASK); 62662306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_HAVE_CONFIGS, 0); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci return cs42l43_soft_reset(cs42l43); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci/* 63262306a36Sopenharmony_ci * Disable the firmware running on the device such that the driver can access 63362306a36Sopenharmony_ci * the registers without fear of the MCU changing them under it. 63462306a36Sopenharmony_ci */ 63562306a36Sopenharmony_cistatic int cs42l43_mcu_disable(struct cs42l43 *cs42l43) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci unsigned int val; 63862306a36Sopenharmony_ci int ret; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG, 64162306a36Sopenharmony_ci CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL); 64262306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION, 64362306a36Sopenharmony_ci CS42L43_FW_MM_CTRL_MCU_SEL_MASK); 64462306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_CONTROL_IND_MASK); 64562306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, 64862306a36Sopenharmony_ci (val & CS42L43_CONTROL_APPLIED_INT_MASK), 64962306a36Sopenharmony_ci CS42L43_MCU_POLL, CS42L43_MCU_CMD_TIMEOUT); 65062306a36Sopenharmony_ci if (ret) { 65162306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to disable firmware: %d, 0x%x\n", ret, val); 65262306a36Sopenharmony_ci return ret; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci /* Soft reset to clear any register state the firmware left behind. */ 65662306a36Sopenharmony_ci return cs42l43_soft_reset(cs42l43); 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/* 66062306a36Sopenharmony_ci * Callback to load firmware updates. 66162306a36Sopenharmony_ci */ 66262306a36Sopenharmony_cistatic void cs42l43_mcu_load_firmware(const struct firmware *firmware, void *context) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci struct cs42l43 *cs42l43 = context; 66562306a36Sopenharmony_ci const struct cs42l43_patch_header *hdr; 66662306a36Sopenharmony_ci unsigned int loadaddr, val; 66762306a36Sopenharmony_ci int ret; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (!firmware) { 67062306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to load firmware\n"); 67162306a36Sopenharmony_ci cs42l43->firmware_error = -ENODEV; 67262306a36Sopenharmony_ci goto err; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci hdr = (const struct cs42l43_patch_header *)&firmware->data[0]; 67662306a36Sopenharmony_ci loadaddr = le32_to_cpu(hdr->load_addr); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci if (le16_to_cpu(hdr->version) != CS42L43_MCU_UPDATE_FORMAT) { 67962306a36Sopenharmony_ci dev_err(cs42l43->dev, "Bad firmware file format: %d\n", hdr->version); 68062306a36Sopenharmony_ci cs42l43->firmware_error = -EINVAL; 68162306a36Sopenharmony_ci goto err_release; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_PATCH_START_ADDR, loadaddr); 68562306a36Sopenharmony_ci regmap_bulk_write(cs42l43->regmap, loadaddr + CS42L43_MCU_UPDATE_OFFSET, 68662306a36Sopenharmony_ci &firmware->data[0], firmware->size / sizeof(u32)); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_PATCH_IND_MASK); 68962306a36Sopenharmony_ci regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, 69262306a36Sopenharmony_ci (val & CS42L43_PATCH_APPLIED_INT_MASK), 69362306a36Sopenharmony_ci CS42L43_MCU_POLL, CS42L43_MCU_UPDATE_TIMEOUT); 69462306a36Sopenharmony_ci if (ret) { 69562306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to update firmware: %d, 0x%x\n", ret, val); 69662306a36Sopenharmony_ci cs42l43->firmware_error = ret; 69762306a36Sopenharmony_ci goto err_release; 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cierr_release: 70162306a36Sopenharmony_ci release_firmware(firmware); 70262306a36Sopenharmony_cierr: 70362306a36Sopenharmony_ci complete(&cs42l43->firmware_download); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci/* 70762306a36Sopenharmony_ci * The process of updating the firmware is split into a series of steps, at the 70862306a36Sopenharmony_ci * end of each step a soft reset of the device might be required which will 70962306a36Sopenharmony_ci * require the driver to wait for the device to re-attach on the SoundWire bus, 71062306a36Sopenharmony_ci * if that control bus is being used. 71162306a36Sopenharmony_ci */ 71262306a36Sopenharmony_cistatic int cs42l43_mcu_update_step(struct cs42l43 *cs42l43) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci unsigned int mcu_rev, bios_rev, boot_status, secure_cfg; 71562306a36Sopenharmony_ci bool patched, shadow; 71662306a36Sopenharmony_ci int ret; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* Clear any stale software interrupt bits. */ 71962306a36Sopenharmony_ci regmap_read(cs42l43->regmap, CS42L43_SOFT_INT, &mcu_rev); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_STATUS, &boot_status); 72262306a36Sopenharmony_ci if (ret) { 72362306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to read boot status: %d\n", ret); 72462306a36Sopenharmony_ci return ret; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ret = regmap_read(cs42l43->regmap, CS42L43_MCU_SW_REV, &mcu_rev); 72862306a36Sopenharmony_ci if (ret) { 72962306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to read firmware revision: %d\n", ret); 73062306a36Sopenharmony_ci return ret; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci bios_rev = (((mcu_rev & CS42L43_BIOS_MAJOR_REV_MASK) << 12) | 73462306a36Sopenharmony_ci ((mcu_rev & CS42L43_BIOS_MINOR_REV_MASK) << 4) | 73562306a36Sopenharmony_ci ((mcu_rev & CS42L43_BIOS_SUBMINOR_REV_MASK) >> 8)) >> 73662306a36Sopenharmony_ci CS42L43_BIOS_MAJOR_REV_SHIFT; 73762306a36Sopenharmony_ci mcu_rev = ((mcu_rev & CS42L43_FW_MAJOR_REV_MASK) << 12) | 73862306a36Sopenharmony_ci ((mcu_rev & CS42L43_FW_MINOR_REV_MASK) << 4) | 73962306a36Sopenharmony_ci ((mcu_rev & CS42L43_FW_SUBMINOR_REV_MASK) >> 8); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* 74262306a36Sopenharmony_ci * The firmware has two revision numbers bringing either of them up to a 74362306a36Sopenharmony_ci * supported version will provide the features the driver requires. 74462306a36Sopenharmony_ci */ 74562306a36Sopenharmony_ci patched = mcu_rev >= CS42L43_MCU_SUPPORTED_REV || 74662306a36Sopenharmony_ci bios_rev >= CS42L43_MCU_SUPPORTED_BIOS_REV; 74762306a36Sopenharmony_ci /* 74862306a36Sopenharmony_ci * Later versions of the firmwware require the driver to access some 74962306a36Sopenharmony_ci * features through a set of shadow registers. 75062306a36Sopenharmony_ci */ 75162306a36Sopenharmony_ci shadow = mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg); 75462306a36Sopenharmony_ci if (ret) { 75562306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to read security settings: %d\n", ret); 75662306a36Sopenharmony_ci return ret; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci cs42l43->hw_lock = secure_cfg & CS42L43_LOCK_HW_STS_MASK; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (!patched && cs42l43->hw_lock) { 76262306a36Sopenharmony_ci dev_err(cs42l43->dev, "Unpatched secure device\n"); 76362306a36Sopenharmony_ci return -EPERM; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci dev_dbg(cs42l43->dev, "Firmware(0x%x, 0x%x) in boot stage %d\n", 76762306a36Sopenharmony_ci mcu_rev, bios_rev, boot_status); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci switch (boot_status) { 77062306a36Sopenharmony_ci case CS42L43_MCU_BOOT_STAGE2: 77162306a36Sopenharmony_ci if (!patched) { 77262306a36Sopenharmony_ci ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, 77362306a36Sopenharmony_ci "cs42l43.bin", cs42l43->dev, 77462306a36Sopenharmony_ci GFP_KERNEL, cs42l43, 77562306a36Sopenharmony_ci cs42l43_mcu_load_firmware); 77662306a36Sopenharmony_ci if (ret) { 77762306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to request firmware: %d\n", ret); 77862306a36Sopenharmony_ci return ret; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci wait_for_completion(&cs42l43->firmware_download); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (cs42l43->firmware_error) 78462306a36Sopenharmony_ci return cs42l43->firmware_error; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return -EAGAIN; 78762306a36Sopenharmony_ci } else { 78862306a36Sopenharmony_ci return cs42l43_mcu_stage_2_3(cs42l43, shadow); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci case CS42L43_MCU_BOOT_STAGE3: 79162306a36Sopenharmony_ci if (patched) 79262306a36Sopenharmony_ci return cs42l43_mcu_disable(cs42l43); 79362306a36Sopenharmony_ci else 79462306a36Sopenharmony_ci return cs42l43_mcu_stage_3_2(cs42l43); 79562306a36Sopenharmony_ci case CS42L43_MCU_BOOT_STAGE4: 79662306a36Sopenharmony_ci return 0; 79762306a36Sopenharmony_ci default: 79862306a36Sopenharmony_ci dev_err(cs42l43->dev, "Invalid boot status: %d\n", boot_status); 79962306a36Sopenharmony_ci return -EINVAL; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci/* 80462306a36Sopenharmony_ci * Update the firmware running on the device. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_cistatic int cs42l43_mcu_update(struct cs42l43 *cs42l43) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci int i, ret; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci for (i = 0; i < CS42L43_MCU_UPDATE_RETRIES; i++) { 81162306a36Sopenharmony_ci ret = cs42l43_mcu_update_step(cs42l43); 81262306a36Sopenharmony_ci if (ret != -EAGAIN) 81362306a36Sopenharmony_ci return ret; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci ret = cs42l43_wait_for_attach(cs42l43); 81662306a36Sopenharmony_ci if (ret) 81762306a36Sopenharmony_ci return ret; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed retrying update\n"); 82162306a36Sopenharmony_ci return -ETIMEDOUT; 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic int cs42l43_irq_config(struct cs42l43 *cs42l43) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci struct irq_data *irq_data; 82762306a36Sopenharmony_ci unsigned long irq_flags; 82862306a36Sopenharmony_ci int ret; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci if (cs42l43->sdw) 83162306a36Sopenharmony_ci cs42l43->irq = cs42l43->sdw->irq; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci cs42l43->irq_chip = cs42l43_irq_chip; 83462306a36Sopenharmony_ci cs42l43->irq_chip.irq_drv_data = cs42l43; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci irq_data = irq_get_irq_data(cs42l43->irq); 83762306a36Sopenharmony_ci if (!irq_data) { 83862306a36Sopenharmony_ci dev_err(cs42l43->dev, "Invalid IRQ: %d\n", cs42l43->irq); 83962306a36Sopenharmony_ci return -EINVAL; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci irq_flags = irqd_get_trigger_type(irq_data); 84362306a36Sopenharmony_ci switch (irq_flags) { 84462306a36Sopenharmony_ci case IRQF_TRIGGER_LOW: 84562306a36Sopenharmony_ci case IRQF_TRIGGER_HIGH: 84662306a36Sopenharmony_ci case IRQF_TRIGGER_RISING: 84762306a36Sopenharmony_ci case IRQF_TRIGGER_FALLING: 84862306a36Sopenharmony_ci break; 84962306a36Sopenharmony_ci case IRQ_TYPE_NONE: 85062306a36Sopenharmony_ci default: 85162306a36Sopenharmony_ci irq_flags = IRQF_TRIGGER_LOW; 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci irq_flags |= IRQF_ONESHOT; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci ret = devm_regmap_add_irq_chip(cs42l43->dev, cs42l43->regmap, 85862306a36Sopenharmony_ci cs42l43->irq, irq_flags, 0, 85962306a36Sopenharmony_ci &cs42l43->irq_chip, &cs42l43->irq_data); 86062306a36Sopenharmony_ci if (ret) { 86162306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to add IRQ chip: %d\n", ret); 86262306a36Sopenharmony_ci return ret; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci dev_dbg(cs42l43->dev, "Configured IRQ %d with flags 0x%lx\n", 86662306a36Sopenharmony_ci cs42l43->irq, irq_flags); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci return 0; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic void cs42l43_boot_work(struct work_struct *work) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct cs42l43 *cs42l43 = container_of(work, struct cs42l43, boot_work); 87462306a36Sopenharmony_ci unsigned int devid, revid, otp; 87562306a36Sopenharmony_ci int ret; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci ret = cs42l43_wait_for_attach(cs42l43); 87862306a36Sopenharmony_ci if (ret) 87962306a36Sopenharmony_ci goto err; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci ret = regmap_read(cs42l43->regmap, CS42L43_DEVID, &devid); 88262306a36Sopenharmony_ci if (ret) { 88362306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to read devid: %d\n", ret); 88462306a36Sopenharmony_ci goto err; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci switch (devid) { 88862306a36Sopenharmony_ci case CS42L43_DEVID_VAL: 88962306a36Sopenharmony_ci break; 89062306a36Sopenharmony_ci default: 89162306a36Sopenharmony_ci dev_err(cs42l43->dev, "Unrecognised devid: 0x%06x\n", devid); 89262306a36Sopenharmony_ci goto err; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci ret = regmap_read(cs42l43->regmap, CS42L43_REVID, &revid); 89662306a36Sopenharmony_ci if (ret) { 89762306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to read rev: %d\n", ret); 89862306a36Sopenharmony_ci goto err; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci ret = regmap_read(cs42l43->regmap, CS42L43_OTP_REVISION_ID, &otp); 90262306a36Sopenharmony_ci if (ret) { 90362306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to read otp rev: %d\n", ret); 90462306a36Sopenharmony_ci goto err; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci dev_info(cs42l43->dev, 90862306a36Sopenharmony_ci "devid: 0x%06x, rev: 0x%02x, otp: 0x%02x\n", devid, revid, otp); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci ret = cs42l43_mcu_update(cs42l43); 91162306a36Sopenharmony_ci if (ret) 91262306a36Sopenharmony_ci goto err; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci ret = regmap_register_patch(cs42l43->regmap, cs42l43_reva_patch, 91562306a36Sopenharmony_ci ARRAY_SIZE(cs42l43_reva_patch)); 91662306a36Sopenharmony_ci if (ret) { 91762306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to apply register patch: %d\n", ret); 91862306a36Sopenharmony_ci goto err; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci ret = cs42l43_irq_config(cs42l43); 92262306a36Sopenharmony_ci if (ret) 92362306a36Sopenharmony_ci goto err; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci ret = devm_mfd_add_devices(cs42l43->dev, PLATFORM_DEVID_NONE, 92662306a36Sopenharmony_ci cs42l43_devs, ARRAY_SIZE(cs42l43_devs), 92762306a36Sopenharmony_ci NULL, 0, NULL); 92862306a36Sopenharmony_ci if (ret) { 92962306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to add subdevices: %d\n", ret); 93062306a36Sopenharmony_ci goto err; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci pm_runtime_mark_last_busy(cs42l43->dev); 93462306a36Sopenharmony_ci pm_runtime_put_autosuspend(cs42l43->dev); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci return; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cierr: 93962306a36Sopenharmony_ci pm_runtime_put_sync(cs42l43->dev); 94062306a36Sopenharmony_ci cs42l43_dev_remove(cs42l43); 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_cistatic int cs42l43_power_up(struct cs42l43 *cs42l43) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci int ret; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci ret = regulator_enable(cs42l43->vdd_p); 94862306a36Sopenharmony_ci if (ret) { 94962306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to enable vdd-p: %d\n", ret); 95062306a36Sopenharmony_ci return ret; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci /* vdd-p must be on for 50uS before any other supply */ 95462306a36Sopenharmony_ci usleep_range(CS42L43_VDDP_DELAY, 2 * CS42L43_VDDP_DELAY); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci gpiod_set_value_cansleep(cs42l43->reset, 1); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); 95962306a36Sopenharmony_ci if (ret) { 96062306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to enable core supplies: %d\n", ret); 96162306a36Sopenharmony_ci goto err_reset; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci ret = regulator_enable(cs42l43->vdd_d); 96562306a36Sopenharmony_ci if (ret) { 96662306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to enable vdd-d: %d\n", ret); 96762306a36Sopenharmony_ci goto err_core_supplies; 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci usleep_range(CS42L43_VDDD_DELAY, 2 * CS42L43_VDDD_DELAY); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci return 0; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cierr_core_supplies: 97562306a36Sopenharmony_ci regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); 97662306a36Sopenharmony_cierr_reset: 97762306a36Sopenharmony_ci gpiod_set_value_cansleep(cs42l43->reset, 0); 97862306a36Sopenharmony_ci regulator_disable(cs42l43->vdd_p); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci return ret; 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic int cs42l43_power_down(struct cs42l43 *cs42l43) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci int ret; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci ret = regulator_disable(cs42l43->vdd_d); 98862306a36Sopenharmony_ci if (ret) { 98962306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to disable vdd-d: %d\n", ret); 99062306a36Sopenharmony_ci return ret; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci ret = regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); 99462306a36Sopenharmony_ci if (ret) { 99562306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to disable core supplies: %d\n", ret); 99662306a36Sopenharmony_ci return ret; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci gpiod_set_value_cansleep(cs42l43->reset, 0); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci ret = regulator_disable(cs42l43->vdd_p); 100262306a36Sopenharmony_ci if (ret) { 100362306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to disable vdd-p: %d\n", ret); 100462306a36Sopenharmony_ci return ret; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci return 0; 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ciint cs42l43_dev_probe(struct cs42l43 *cs42l43) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci int i, ret; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci dev_set_drvdata(cs42l43->dev, cs42l43); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci mutex_init(&cs42l43->pll_lock); 101762306a36Sopenharmony_ci init_completion(&cs42l43->device_attach); 101862306a36Sopenharmony_ci init_completion(&cs42l43->device_detach); 101962306a36Sopenharmony_ci init_completion(&cs42l43->firmware_download); 102062306a36Sopenharmony_ci INIT_WORK(&cs42l43->boot_work, cs42l43_boot_work); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci regcache_cache_only(cs42l43->regmap, true); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_LOW); 102562306a36Sopenharmony_ci if (IS_ERR(cs42l43->reset)) 102662306a36Sopenharmony_ci return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset), 102762306a36Sopenharmony_ci "Failed to get reset\n"); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p"); 103062306a36Sopenharmony_ci if (IS_ERR(cs42l43->vdd_p)) 103162306a36Sopenharmony_ci return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p), 103262306a36Sopenharmony_ci "Failed to get vdd-p\n"); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci cs42l43->vdd_d = devm_regulator_get(cs42l43->dev, "vdd-d"); 103562306a36Sopenharmony_ci if (IS_ERR(cs42l43->vdd_d)) 103662306a36Sopenharmony_ci return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_d), 103762306a36Sopenharmony_ci "Failed to get vdd-d\n"); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(cs42l43_core_supplies) != CS42L43_N_SUPPLIES); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci for (i = 0; i < CS42L43_N_SUPPLIES; i++) 104262306a36Sopenharmony_ci cs42l43->core_supplies[i].supply = cs42l43_core_supplies[i]; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci ret = devm_regulator_bulk_get(cs42l43->dev, CS42L43_N_SUPPLIES, 104562306a36Sopenharmony_ci cs42l43->core_supplies); 104662306a36Sopenharmony_ci if (ret) 104762306a36Sopenharmony_ci return dev_err_probe(cs42l43->dev, ret, 104862306a36Sopenharmony_ci "Failed to get core supplies\n"); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci ret = cs42l43_power_up(cs42l43); 105162306a36Sopenharmony_ci if (ret) 105262306a36Sopenharmony_ci return ret; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME); 105562306a36Sopenharmony_ci pm_runtime_use_autosuspend(cs42l43->dev); 105662306a36Sopenharmony_ci pm_runtime_set_active(cs42l43->dev); 105762306a36Sopenharmony_ci /* 105862306a36Sopenharmony_ci * The device is already powered up, but keep it from suspending until 105962306a36Sopenharmony_ci * the boot work runs. 106062306a36Sopenharmony_ci */ 106162306a36Sopenharmony_ci pm_runtime_get_noresume(cs42l43->dev); 106262306a36Sopenharmony_ci devm_pm_runtime_enable(cs42l43->dev); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci queue_work(system_long_wq, &cs42l43->boot_work); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci return 0; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, MFD_CS42L43); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_civoid cs42l43_dev_remove(struct cs42l43 *cs42l43) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci cs42l43_power_down(cs42l43); 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, MFD_CS42L43); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic int cs42l43_suspend(struct device *dev) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci struct cs42l43 *cs42l43 = dev_get_drvdata(dev); 107962306a36Sopenharmony_ci int ret; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci /* 108262306a36Sopenharmony_ci * Don't care about being resumed here, but the driver does want 108362306a36Sopenharmony_ci * force_resume to always trigger an actual resume, so that register 108462306a36Sopenharmony_ci * state for the MCU/GPIOs is returned as soon as possible after system 108562306a36Sopenharmony_ci * resume. force_resume will resume if the reference count is resumed on 108662306a36Sopenharmony_ci * suspend hence the get_noresume. 108762306a36Sopenharmony_ci */ 108862306a36Sopenharmony_ci pm_runtime_get_noresume(dev); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci ret = pm_runtime_force_suspend(dev); 109162306a36Sopenharmony_ci if (ret) { 109262306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to force suspend: %d\n", ret); 109362306a36Sopenharmony_ci pm_runtime_put_noidle(dev); 109462306a36Sopenharmony_ci return ret; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci pm_runtime_put_noidle(dev); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci ret = cs42l43_power_down(cs42l43); 110062306a36Sopenharmony_ci if (ret) 110162306a36Sopenharmony_ci return ret; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return 0; 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistatic int cs42l43_resume(struct device *dev) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci struct cs42l43 *cs42l43 = dev_get_drvdata(dev); 110962306a36Sopenharmony_ci int ret; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci ret = cs42l43_power_up(cs42l43); 111262306a36Sopenharmony_ci if (ret) 111362306a36Sopenharmony_ci return ret; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci ret = pm_runtime_force_resume(dev); 111662306a36Sopenharmony_ci if (ret) { 111762306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to force resume: %d\n", ret); 111862306a36Sopenharmony_ci return ret; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci return 0; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic int cs42l43_runtime_suspend(struct device *dev) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci struct cs42l43 *cs42l43 = dev_get_drvdata(dev); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci /* 112962306a36Sopenharmony_ci * Whilst the driver doesn't power the chip down here, going into runtime 113062306a36Sopenharmony_ci * suspend lets the SoundWire bus power down, which means the driver 113162306a36Sopenharmony_ci * can't communicate with the device any more. 113262306a36Sopenharmony_ci */ 113362306a36Sopenharmony_ci regcache_cache_only(cs42l43->regmap, true); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci return 0; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic int cs42l43_runtime_resume(struct device *dev) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci struct cs42l43 *cs42l43 = dev_get_drvdata(dev); 114162306a36Sopenharmony_ci unsigned int reset_canary; 114262306a36Sopenharmony_ci int ret; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci ret = cs42l43_wait_for_attach(cs42l43); 114562306a36Sopenharmony_ci if (ret) 114662306a36Sopenharmony_ci return ret; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci ret = regmap_read(cs42l43->regmap, CS42L43_RELID, &reset_canary); 114962306a36Sopenharmony_ci if (ret) { 115062306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to check reset canary: %d\n", ret); 115162306a36Sopenharmony_ci goto err; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (!reset_canary) { 115562306a36Sopenharmony_ci /* 115662306a36Sopenharmony_ci * If the canary has cleared the chip has reset, re-handle the 115762306a36Sopenharmony_ci * MCU and mark the cache as dirty to indicate the chip reset. 115862306a36Sopenharmony_ci */ 115962306a36Sopenharmony_ci ret = cs42l43_mcu_update(cs42l43); 116062306a36Sopenharmony_ci if (ret) 116162306a36Sopenharmony_ci goto err; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci regcache_mark_dirty(cs42l43->regmap); 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci ret = regcache_sync(cs42l43->regmap); 116762306a36Sopenharmony_ci if (ret) { 116862306a36Sopenharmony_ci dev_err(cs42l43->dev, "Failed to restore register cache: %d\n", ret); 116962306a36Sopenharmony_ci goto err; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci return 0; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_cierr: 117562306a36Sopenharmony_ci regcache_cache_only(cs42l43->regmap, true); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci return ret; 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ciEXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = { 118162306a36Sopenharmony_ci SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume) 118262306a36Sopenharmony_ci RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL) 118362306a36Sopenharmony_ci}; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ciMODULE_DESCRIPTION("CS42L43 Core Driver"); 118662306a36Sopenharmony_ciMODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>"); 118762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 118862306a36Sopenharmony_ciMODULE_FIRMWARE("cs42l43.bin"); 1189