// SPDX-License-Identifier: GPL-2.0-only // // Components shared between ASoC and HDA CS35L56 drivers // // Copyright (C) 2023 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. #include #include #include #include "cs35l56.h" static const struct reg_default cs35l56_reg_defaults[] = { { CS35L56_ASP1_ENABLES1, 0x00000000 }, { CS35L56_ASP1_CONTROL1, 0x00000028 }, { CS35L56_ASP1_CONTROL2, 0x18180200 }, { CS35L56_ASP1_CONTROL3, 0x00000002 }, { CS35L56_ASP1_FRAME_CONTROL1, 0x03020100 }, { CS35L56_ASP1_FRAME_CONTROL5, 0x00020100 }, { CS35L56_ASP1_DATA_CONTROL1, 0x00000018 }, { CS35L56_ASP1_DATA_CONTROL5, 0x00000018 }, { CS35L56_ASP1TX1_INPUT, 0x00000018 }, { CS35L56_ASP1TX2_INPUT, 0x00000019 }, { CS35L56_ASP1TX3_INPUT, 0x00000020 }, { CS35L56_ASP1TX4_INPUT, 0x00000028 }, { CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 }, { CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 }, { CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 }, { CS35L56_SWIRE_DP3_CH4_INPUT, 0x00000028 }, { CS35L56_SWIRE_DP3_CH5_INPUT, 0x00000018 }, { CS35L56_SWIRE_DP3_CH6_INPUT, 0x00000018 }, { CS35L56_IRQ1_CFG, 0x00000000 }, { CS35L56_IRQ1_MASK_1, 0x83ffffff }, { CS35L56_IRQ1_MASK_2, 0xffff7fff }, { CS35L56_IRQ1_MASK_4, 0xe0ffffff }, { CS35L56_IRQ1_MASK_8, 0xfc000fff }, { CS35L56_IRQ1_MASK_18, 0x1f7df0ff }, { CS35L56_IRQ1_MASK_20, 0x15c00000 }, /* CS35L56_MAIN_RENDER_USER_MUTE - soft register, no default */ /* CS35L56_MAIN_RENDER_USER_VOLUME - soft register, no default */ /* CS35L56_MAIN_POSTURE_NUMBER - soft register, no default */ }; /* * The Ax devices have different default register values to that of B0, * establish a common set of register defaults. */ static const struct reg_sequence cs35l56_reva_patch[] = { { CS35L56_SWIRE_DP3_CH5_INPUT, 0x00000018 }, { CS35L56_SWIRE_DP3_CH6_INPUT, 0x00000018 }, }; void cs35l56_patch(struct device *dev, struct regmap *regmap, u8 revid) { int ret; if (revid >= CS35L56_REVID_B0) return; ret = regmap_register_patch(regmap, cs35l56_reva_patch, ARRAY_SIZE(cs35l56_reva_patch)); if (ret) dev_err(dev, "Failed to apply patch: %d\n", ret); } EXPORT_SYMBOL_NS_GPL(cs35l56_patch, SND_SOC_CS35L56_SHARED); static bool cs35l56_is_dsp_memory(unsigned int reg) { switch (reg) { case CS35L56_DSP1_XMEM_PACKED_0 ... CS35L56_DSP1_XMEM_PACKED_6143: case CS35L56_DSP1_XMEM_UNPACKED32_0 ... CS35L56_DSP1_XMEM_UNPACKED32_4095: case CS35L56_DSP1_XMEM_UNPACKED24_0 ... CS35L56_DSP1_XMEM_UNPACKED24_8191: case CS35L56_DSP1_YMEM_PACKED_0 ... CS35L56_DSP1_YMEM_PACKED_4604: case CS35L56_DSP1_YMEM_UNPACKED32_0 ... CS35L56_DSP1_YMEM_UNPACKED32_3070: case CS35L56_DSP1_YMEM_UNPACKED24_0 ... CS35L56_DSP1_YMEM_UNPACKED24_6141: case CS35L56_DSP1_PMEM_0 ... CS35L56_DSP1_PMEM_5114: return true; default: return false; } } static bool cs35l56_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L56_DEVID: case CS35L56_REVID: case CS35L56_RELID: case CS35L56_OTPID: case CS35L56_SFT_RESET: case CS35L56_GLOBAL_ENABLES: case CS35L56_BLOCK_ENABLES: case CS35L56_BLOCK_ENABLES2: case CS35L56_REFCLK_INPUT: case CS35L56_GLOBAL_SAMPLE_RATE: case CS35L56_ASP1_ENABLES1: case CS35L56_ASP1_CONTROL1: case CS35L56_ASP1_CONTROL2: case CS35L56_ASP1_CONTROL3: case CS35L56_ASP1_FRAME_CONTROL1: case CS35L56_ASP1_FRAME_CONTROL5: case CS35L56_ASP1_DATA_CONTROL1: case CS35L56_ASP1_DATA_CONTROL5: case CS35L56_DACPCM1_INPUT: case CS35L56_DACPCM2_INPUT: case CS35L56_ASP1TX1_INPUT: case CS35L56_ASP1TX2_INPUT: case CS35L56_ASP1TX3_INPUT: case CS35L56_ASP1TX4_INPUT: case CS35L56_DSP1RX1_INPUT: case CS35L56_DSP1RX2_INPUT: case CS35L56_SWIRE_DP3_CH1_INPUT: case CS35L56_SWIRE_DP3_CH2_INPUT: case CS35L56_SWIRE_DP3_CH3_INPUT: case CS35L56_SWIRE_DP3_CH4_INPUT: case CS35L56_SWIRE_DP3_CH5_INPUT: case CS35L56_SWIRE_DP3_CH6_INPUT: case CS35L56_IRQ1_CFG: case CS35L56_IRQ1_STATUS: case CS35L56_IRQ1_EINT_1 ... CS35L56_IRQ1_EINT_8: case CS35L56_IRQ1_EINT_18: case CS35L56_IRQ1_EINT_20: case CS35L56_IRQ1_MASK_1: case CS35L56_IRQ1_MASK_2: case CS35L56_IRQ1_MASK_4: case CS35L56_IRQ1_MASK_8: case CS35L56_IRQ1_MASK_18: case CS35L56_IRQ1_MASK_20: case CS35L56_DSP_VIRTUAL1_MBOX_1: case CS35L56_DSP_VIRTUAL1_MBOX_2: case CS35L56_DSP_VIRTUAL1_MBOX_3: case CS35L56_DSP_VIRTUAL1_MBOX_4: case CS35L56_DSP_VIRTUAL1_MBOX_5: case CS35L56_DSP_VIRTUAL1_MBOX_6: case CS35L56_DSP_VIRTUAL1_MBOX_7: case CS35L56_DSP_VIRTUAL1_MBOX_8: case CS35L56_DSP_RESTRICT_STS1: case CS35L56_DSP1_SYS_INFO_ID ... CS35L56_DSP1_SYS_INFO_END: case CS35L56_DSP1_AHBM_WINDOW_DEBUG_0: case CS35L56_DSP1_AHBM_WINDOW_DEBUG_1: case CS35L56_DSP1_SCRATCH1: case CS35L56_DSP1_SCRATCH2: case CS35L56_DSP1_SCRATCH3: case CS35L56_DSP1_SCRATCH4: return true; default: return cs35l56_is_dsp_memory(reg); } } static bool cs35l56_precious_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L56_DSP1_XMEM_PACKED_0 ... CS35L56_DSP1_XMEM_PACKED_6143: case CS35L56_DSP1_YMEM_PACKED_0 ... CS35L56_DSP1_YMEM_PACKED_4604: case CS35L56_DSP1_PMEM_0 ... CS35L56_DSP1_PMEM_5114: return true; default: return false; } } static bool cs35l56_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case CS35L56_DEVID: case CS35L56_REVID: case CS35L56_RELID: case CS35L56_OTPID: case CS35L56_SFT_RESET: case CS35L56_GLOBAL_ENABLES: /* owned by firmware */ case CS35L56_BLOCK_ENABLES: /* owned by firmware */ case CS35L56_BLOCK_ENABLES2: /* owned by firmware */ case CS35L56_REFCLK_INPUT: /* owned by firmware */ case CS35L56_GLOBAL_SAMPLE_RATE: /* owned by firmware */ case CS35L56_DACPCM1_INPUT: /* owned by firmware */ case CS35L56_DACPCM2_INPUT: /* owned by firmware */ case CS35L56_DSP1RX1_INPUT: /* owned by firmware */ case CS35L56_DSP1RX2_INPUT: /* owned by firmware */ case CS35L56_IRQ1_STATUS: case CS35L56_IRQ1_EINT_1 ... CS35L56_IRQ1_EINT_8: case CS35L56_IRQ1_EINT_18: case CS35L56_IRQ1_EINT_20: case CS35L56_DSP_VIRTUAL1_MBOX_1: case CS35L56_DSP_VIRTUAL1_MBOX_2: case CS35L56_DSP_VIRTUAL1_MBOX_3: case CS35L56_DSP_VIRTUAL1_MBOX_4: case CS35L56_DSP_VIRTUAL1_MBOX_5: case CS35L56_DSP_VIRTUAL1_MBOX_6: case CS35L56_DSP_VIRTUAL1_MBOX_7: case CS35L56_DSP_VIRTUAL1_MBOX_8: case CS35L56_DSP_RESTRICT_STS1: case CS35L56_DSP1_SYS_INFO_ID ... CS35L56_DSP1_SYS_INFO_END: case CS35L56_DSP1_AHBM_WINDOW_DEBUG_0: case CS35L56_DSP1_AHBM_WINDOW_DEBUG_1: case CS35L56_DSP1_SCRATCH1: case CS35L56_DSP1_SCRATCH2: case CS35L56_DSP1_SCRATCH3: case CS35L56_DSP1_SCRATCH4: return true; case CS35L56_MAIN_RENDER_USER_MUTE: case CS35L56_MAIN_RENDER_USER_VOLUME: case CS35L56_MAIN_POSTURE_NUMBER: return false; default: return cs35l56_is_dsp_memory(reg); } } static const u32 cs35l56_firmware_registers[] = { CS35L56_MAIN_RENDER_USER_MUTE, CS35L56_MAIN_RENDER_USER_VOLUME, CS35L56_MAIN_POSTURE_NUMBER, }; void cs35l56_reread_firmware_registers(struct device *dev, struct regmap *regmap) { int i; unsigned int val; for (i = 0; i < ARRAY_SIZE(cs35l56_firmware_registers); i++) { regmap_read(regmap, cs35l56_firmware_registers[i], &val); dev_dbg(dev, "%s: %d: %#x: %#x\n", __func__, i, cs35l56_firmware_registers[i], val); } } EXPORT_SYMBOL_NS_GPL(cs35l56_reread_firmware_registers, SND_SOC_CS35L56_SHARED); const struct cs_dsp_region cs35l56_dsp1_regions[] = { { .type = WMFW_HALO_PM_PACKED, .base = CS35L56_DSP1_PMEM_0 }, { .type = WMFW_HALO_XM_PACKED, .base = CS35L56_DSP1_XMEM_PACKED_0 }, { .type = WMFW_HALO_YM_PACKED, .base = CS35L56_DSP1_YMEM_PACKED_0 }, { .type = WMFW_ADSP2_XM, .base = CS35L56_DSP1_XMEM_UNPACKED24_0 }, { .type = WMFW_ADSP2_YM, .base = CS35L56_DSP1_YMEM_UNPACKED24_0 }, }; EXPORT_SYMBOL_NS_GPL(cs35l56_dsp1_regions, SND_SOC_CS35L56_SHARED); static const u32 cs35l56_bclk_valid_for_pll_freq_table[] = { [0x0C] = 128000, [0x0F] = 256000, [0x11] = 384000, [0x12] = 512000, [0x15] = 768000, [0x17] = 1024000, [0x1A] = 1500000, [0x1B] = 1536000, [0x1C] = 2000000, [0x1D] = 2048000, [0x1E] = 2400000, [0x20] = 3000000, [0x21] = 3072000, [0x23] = 4000000, [0x24] = 4096000, [0x25] = 4800000, [0x27] = 6000000, [0x28] = 6144000, [0x29] = 6250000, [0x2A] = 6400000, [0x2E] = 8000000, [0x2F] = 8192000, [0x30] = 9600000, [0x32] = 12000000, [0x33] = 12288000, [0x37] = 13500000, [0x38] = 19200000, [0x39] = 22579200, [0x3B] = 24576000, }; int cs35l56_get_bclk_freq_id(unsigned int freq) { int i; if (freq == 0) return -EINVAL; /* The BCLK frequency must be a valid PLL REFCLK */ for (i = 0; i < ARRAY_SIZE(cs35l56_bclk_valid_for_pll_freq_table); ++i) { if (cs35l56_bclk_valid_for_pll_freq_table[i] == freq) return i; } return -EINVAL; } EXPORT_SYMBOL_NS_GPL(cs35l56_get_bclk_freq_id, SND_SOC_CS35L56_SHARED); static const char * const cs35l56_supplies[/* auto-sized */] = { "VDD_P", "VDD_IO", "VDD_A", }; void cs35l56_fill_supply_names(struct regulator_bulk_data *data) { int i; BUILD_BUG_ON(ARRAY_SIZE(cs35l56_supplies) != CS35L56_NUM_BULK_SUPPLIES); for (i = 0; i < ARRAY_SIZE(cs35l56_supplies); i++) data[i].supply = cs35l56_supplies[i]; } EXPORT_SYMBOL_NS_GPL(cs35l56_fill_supply_names, SND_SOC_CS35L56_SHARED); const char * const cs35l56_tx_input_texts[] = { "None", "ASP1RX1", "ASP1RX2", "VMON", "IMON", "ERRVOL", "CLASSH", "VDDBMON", "VBSTMON", "DSP1TX1", "DSP1TX2", "DSP1TX3", "DSP1TX4", "DSP1TX5", "DSP1TX6", "DSP1TX7", "DSP1TX8", "TEMPMON", "INTERPOLATOR", "SDW1RX1", "SDW1RX2", "SDW2RX1", }; EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_texts, SND_SOC_CS35L56_SHARED); const unsigned int cs35l56_tx_input_values[] = { CS35L56_INPUT_SRC_NONE, CS35L56_INPUT_SRC_ASP1RX1, CS35L56_INPUT_SRC_ASP1RX2, CS35L56_INPUT_SRC_VMON, CS35L56_INPUT_SRC_IMON, CS35L56_INPUT_SRC_ERR_VOL, CS35L56_INPUT_SRC_CLASSH, CS35L56_INPUT_SRC_VDDBMON, CS35L56_INPUT_SRC_VBSTMON, CS35L56_INPUT_SRC_DSP1TX1, CS35L56_INPUT_SRC_DSP1TX2, CS35L56_INPUT_SRC_DSP1TX3, CS35L56_INPUT_SRC_DSP1TX4, CS35L56_INPUT_SRC_DSP1TX5, CS35L56_INPUT_SRC_DSP1TX6, CS35L56_INPUT_SRC_DSP1TX7, CS35L56_INPUT_SRC_DSP1TX8, CS35L56_INPUT_SRC_TEMPMON, CS35L56_INPUT_SRC_INTERPOLATOR, CS35L56_INPUT_SRC_SWIRE_RX1, CS35L56_INPUT_SRC_SWIRE_RX2, CS35L56_INPUT_SRC_SWIRE_RX3, }; EXPORT_SYMBOL_NS_GPL(cs35l56_tx_input_values, SND_SOC_CS35L56_SHARED); struct regmap_config cs35l56_regmap_i2c = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .reg_format_endian = REGMAP_ENDIAN_BIG, .val_format_endian = REGMAP_ENDIAN_BIG, .max_register = CS35L56_DSP1_PMEM_5114, .reg_defaults = cs35l56_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs35l56_reg_defaults), .volatile_reg = cs35l56_volatile_reg, .readable_reg = cs35l56_readable_reg, .precious_reg = cs35l56_precious_reg, .cache_type = REGCACHE_RBTREE, }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_i2c, SND_SOC_CS35L56_SHARED); struct regmap_config cs35l56_regmap_spi = { .reg_bits = 32, .val_bits = 32, .pad_bits = 16, .reg_stride = 4, .reg_format_endian = REGMAP_ENDIAN_BIG, .val_format_endian = REGMAP_ENDIAN_BIG, .max_register = CS35L56_DSP1_PMEM_5114, .reg_defaults = cs35l56_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs35l56_reg_defaults), .volatile_reg = cs35l56_volatile_reg, .readable_reg = cs35l56_readable_reg, .precious_reg = cs35l56_precious_reg, .cache_type = REGCACHE_RBTREE, }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_spi, SND_SOC_CS35L56_SHARED); struct regmap_config cs35l56_regmap_sdw = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .reg_format_endian = REGMAP_ENDIAN_LITTLE, .val_format_endian = REGMAP_ENDIAN_BIG, .max_register = CS35L56_DSP1_PMEM_5114, .reg_defaults = cs35l56_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs35l56_reg_defaults), .volatile_reg = cs35l56_volatile_reg, .readable_reg = cs35l56_readable_reg, .precious_reg = cs35l56_precious_reg, .cache_type = REGCACHE_RBTREE, }; EXPORT_SYMBOL_NS_GPL(cs35l56_regmap_sdw, SND_SOC_CS35L56_SHARED); MODULE_DESCRIPTION("ASoC CS35L56 Shared"); MODULE_AUTHOR("Richard Fitzgerald "); MODULE_AUTHOR("Simon Trimmer "); MODULE_LICENSE("GPL");