diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml | 1 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/sound/audio-graph-port.yaml | 9 | ||||
-rw-r--r-- | include/dt-bindings/sound/audio-graph.h | 26 | ||||
-rw-r--r-- | include/sound/simple_card_utils.h | 4 | ||||
-rw-r--r-- | sound/soc/codecs/lpass-macro-common.c | 8 | ||||
-rw-r--r-- | sound/soc/codecs/lpass-macro-common.h | 7 | ||||
-rw-r--r-- | sound/soc/codecs/lpass-rx-macro.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/lpass-va-macro.c | 3 | ||||
-rw-r--r-- | sound/soc/codecs/rt712-sdca-sdw.c | 36 | ||||
-rw-r--r-- | sound/soc/codecs/rt712-sdca-sdw.h | 95 | ||||
-rw-r--r-- | sound/soc/codecs/rt712-sdca.c | 665 | ||||
-rw-r--r-- | sound/soc/codecs/rt712-sdca.h | 48 | ||||
-rw-r--r-- | sound/soc/generic/audio-graph-card.c | 13 | ||||
-rw-r--r-- | sound/soc/generic/audio-graph-card2.c | 13 | ||||
-rw-r--r-- | sound/soc/generic/simple-card-utils.c | 71 | ||||
-rw-r--r-- | sound/soc/generic/simple-card.c | 10 | ||||
-rw-r--r-- | sound/soc/qcom/lpass-cpu.c | 4 |
17 files changed, 864 insertions, 151 deletions
diff --git a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml index d4277d342e69..0ecdaf7190e9 100644 --- a/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml +++ b/Documentation/devicetree/bindings/sound/amlogic,gx-sound-card.yaml @@ -23,7 +23,6 @@ properties: audio-widgets: $ref: /schemas/types.yaml#/definitions/non-unique-string-array - minItems: 2 description: |- A list off component DAPM widget. Each entry is a pair of strings, the first being the widget type, the second being the widget name diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index 28b27e7e45de..d1cbfc5edd3a 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -25,6 +25,15 @@ definitions: capture-only: description: port connection used only for capture $ref: /schemas/types.yaml#/definitions/flag + link-trigger-order: + description: trigger order for both start/stop + $ref: /schemas/types.yaml#/definitions/uint32-array + link-trigger-order-start: + description: trigger order for start + $ref: /schemas/types.yaml#/definitions/uint32-array + link-trigger-order-stop: + description: trigger order for stop + $ref: /schemas/types.yaml#/definitions/uint32-array endpoint-base: allOf: diff --git a/include/dt-bindings/sound/audio-graph.h b/include/dt-bindings/sound/audio-graph.h new file mode 100644 index 000000000000..bdb70c6b7332 --- /dev/null +++ b/include/dt-bindings/sound/audio-graph.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * audio-graph.h + * + * Copyright (c) 2024 Kuninori Morimoto <[email protected]> + */ +#ifndef __AUDIO_GRAPH_H +#define __AUDIO_GRAPH_H + +/* + * used in + * link-trigger-order + * link-trigger-order-start + * link-trigger-order-stop + * + * default is + * link-trigger-order = <SND_SOC_TRIGGER_LINK + * SND_SOC_TRIGGER_COMPONENT + * SND_SOC_TRIGGER_DAI>; + */ +#define SND_SOC_TRIGGER_LINK 0 +#define SND_SOC_TRIGGER_COMPONENT 1 +#define SND_SOC_TRIGGER_DAI 2 +#define SND_SOC_TRIGGER_SIZE 3 /* shoud be last */ + +#endif /* __AUDIO_GRAPH_H */ diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index 0a6435ac5c5f..3360d9eab068 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -199,6 +199,10 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep, void graph_util_parse_link_direction(struct device_node *np, bool *is_playback_only, bool *is_capture_only); +void graph_util_parse_trigger_order(struct simple_util_priv *priv, + struct device_node *np, + enum snd_soc_trigger_order *trigger_start, + enum snd_soc_trigger_order *trigger_stop); #ifdef DEBUG static inline void simple_util_debug_dai(struct simple_util_priv *priv, diff --git a/sound/soc/codecs/lpass-macro-common.c b/sound/soc/codecs/lpass-macro-common.c index 8b038a99a8f9..6e3b8d0897dd 100644 --- a/sound/soc/codecs/lpass-macro-common.c +++ b/sound/soc/codecs/lpass-macro-common.c @@ -12,7 +12,7 @@ #include "lpass-macro-common.h" static DEFINE_MUTEX(lpass_codec_mutex); -static int lpass_codec_version; +static enum lpass_codec_version lpass_codec_version; struct lpass_macro *lpass_macro_pds_init(struct device *dev) { @@ -69,7 +69,7 @@ void lpass_macro_pds_exit(struct lpass_macro *pds) } EXPORT_SYMBOL_GPL(lpass_macro_pds_exit); -void lpass_macro_set_codec_version(int version) +void lpass_macro_set_codec_version(enum lpass_codec_version version) { mutex_lock(&lpass_codec_mutex); lpass_codec_version = version; @@ -77,9 +77,9 @@ void lpass_macro_set_codec_version(int version) } EXPORT_SYMBOL_GPL(lpass_macro_set_codec_version); -int lpass_macro_get_codec_version(void) +enum lpass_codec_version lpass_macro_get_codec_version(void) { - int ver; + enum lpass_codec_version ver; mutex_lock(&lpass_codec_mutex); ver = lpass_codec_version; diff --git a/sound/soc/codecs/lpass-macro-common.h b/sound/soc/codecs/lpass-macro-common.h index f6f1bfe8eb77..3aa9737f2737 100644 --- a/sound/soc/codecs/lpass-macro-common.h +++ b/sound/soc/codecs/lpass-macro-common.h @@ -19,7 +19,8 @@ enum lpass_version { }; enum lpass_codec_version { - LPASS_CODEC_VERSION_1_0 = 1, + LPASS_CODEC_VERSION_UNKNOWN, + LPASS_CODEC_VERSION_1_0, LPASS_CODEC_VERSION_1_1, LPASS_CODEC_VERSION_1_2, LPASS_CODEC_VERSION_2_0, @@ -37,8 +38,8 @@ struct lpass_macro { struct lpass_macro *lpass_macro_pds_init(struct device *dev); void lpass_macro_pds_exit(struct lpass_macro *pds); -void lpass_macro_set_codec_version(int version); -int lpass_macro_get_codec_version(void); +void lpass_macro_set_codec_version(enum lpass_codec_version version); +enum lpass_codec_version lpass_macro_get_codec_version(void); static inline const char *lpass_macro_get_codec_version_string(int version) { diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index 8af86509a3ff..9c4f0763675d 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -642,7 +642,7 @@ struct rx_macro { int rx_mclk_users; int clsh_users; int rx_mclk_cnt; - int codec_version; + enum lpass_codec_version codec_version; int rxn_reg_stride; bool is_ear_mode_on; bool hph_pwr_mode; diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index b0006f4ce8a2..b852cc7ffad9 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1463,7 +1463,8 @@ undefined_rate: static void va_macro_set_lpass_codec_version(struct va_macro *va) { - int core_id_0 = 0, core_id_1 = 0, core_id_2 = 0, version; + int core_id_0 = 0, core_id_1 = 0, core_id_2 = 0; + int version = LPASS_CODEC_VERSION_UNKNOWN; regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_0, &core_id_0); regmap_read(va->regmap, CDC_VA_TOP_CSR_CORE_ID_1, &core_id_1); diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index ce337db86d1a..90d5aaddbd5b 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -34,6 +34,10 @@ static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg) case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0): case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2: return true; default: @@ -56,6 +60,10 @@ static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg) case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0): case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0): case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2: return true; default: @@ -78,13 +86,21 @@ static bool rt712_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x5c00000 ... 0x5c0009a: case 0x5d00000 ... 0x5d00009: case 0x5f00000 ... 0x5f00030: - case 0x6100000 ... 0x6100068: - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L): - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R): - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L): - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R): - case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L): - case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R): + case 0x6100000 ... 0x61000f1: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04): return true; default: return false; @@ -96,7 +112,9 @@ static bool rt712_sdca_mbq_volatile_register(struct device *dev, unsigned int re switch (reg) { case 0x2000000: case 0x200001a: + case 0x2000020: case 0x2000024: + case 0x2000030: case 0x2000046: case 0x200008a: case 0x5800000: @@ -178,13 +196,15 @@ static int rt712_sdca_read_prop(struct sdw_slave *slave) unsigned long addr; struct sdw_dpn_prop *dpn; + sdw_slave_read_prop(slave); + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; prop->paging_support = true; /* first we need to allocate memory for set bits in port lists */ - prop->source_ports = BIT(4); /* BITMAP: 00010000 */ + prop->source_ports = BIT(8) | BIT(4); /* BITMAP: 100010000 */ prop->sink_ports = BIT(3) | BIT(1); /* BITMAP: 00001010 */ nval = hweight32(prop->source_ports); diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h index 4be22ccd8561..99fd2d67f04d 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.h +++ b/sound/soc/codecs/rt712-sdca-sdw.h @@ -12,68 +12,31 @@ #include <linux/soundwire/sdw_registers.h> static const struct reg_default rt712_sdca_reg_defaults[] = { - { 0x201a, 0x00 }, - { 0x201b, 0x00 }, - { 0x201c, 0x00 }, - { 0x201d, 0x00 }, - { 0x201e, 0x00 }, - { 0x201f, 0x00 }, - { 0x2029, 0x00 }, - { 0x202a, 0x00 }, - { 0x202d, 0x00 }, - { 0x202e, 0x00 }, - { 0x202f, 0x00 }, - { 0x2030, 0x00 }, - { 0x2031, 0x00 }, - { 0x2032, 0x00 }, - { 0x2033, 0x00 }, - { 0x2034, 0x00 }, - { 0x2230, 0x00 }, - { 0x2231, 0x2f }, - { 0x2232, 0x80 }, - { 0x2f01, 0x00 }, - { 0x2f02, 0x09 }, - { 0x2f03, 0x00 }, - { 0x2f04, 0x00 }, - { 0x2f05, 0x0b }, - { 0x2f06, 0x01 }, - { 0x2f08, 0x00 }, - { 0x2f09, 0x00 }, - { 0x2f0a, 0x01 }, - { 0x2f35, 0x01 }, - { 0x2f36, 0xcf }, - { 0x2f50, 0x0f }, - { 0x2f54, 0x01 }, - { 0x2f58, 0x07 }, - { 0x2f59, 0x09 }, - { 0x2f5a, 0x01 }, - { 0x2f5b, 0x07 }, - { 0x2f5c, 0x05 }, - { 0x2f5d, 0x05 }, - { 0x3201, 0x01 }, - { 0x320c, 0x00 }, - { 0x3301, 0x01 }, - { 0x3302, 0x00 }, - { 0x3303, 0x1f }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_PDE23, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L), 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R), 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, }; static const struct reg_default rt712_sdca_mbq_defaults[] = { { 0x2000004, 0xaa01 }, { 0x200000e, 0x21e0 }, - { 0x2000024, 0x01ba }, { 0x200004a, 0x8830 }, { 0x2000067, 0xf100 }, { 0x5800000, 0x1893 }, @@ -81,12 +44,8 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = { { 0x5b00005, 0x0000 }, { 0x5b00029, 0x3fff }, { 0x5b0002a, 0xf000 }, - { 0x5f00008, 0x7000 }, + { 0x6100000, 0x04e4 }, { 0x610000e, 0x0007 }, - { 0x6100022, 0x2828 }, - { 0x6100023, 0x2929 }, - { 0x6100026, 0x2c29 }, - { 0x610002c, 0x4150 }, { 0x6100045, 0x0860 }, { 0x6100046, 0x0029 }, { 0x6100053, 0x3fff }, @@ -95,14 +54,22 @@ static const struct reg_default rt712_sdca_mbq_defaults[] = { { 0x6100064, 0x8000 }, { 0x6100065, 0x0000 }, { 0x6100067, 0xff12 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 }, }; #endif /* __RT712_SDW_H__ */ diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index b503de9fda80..e210c574bb74 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -82,7 +82,8 @@ static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712) dev = regmap_get_device(regmap); /* Set HP-JD source from JD1 */ - rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a); + if (rt712->version_id == RT712_VA) + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a); /* FSM switch to calibration manual mode */ rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_FSM_CTL, 0x4100); @@ -198,11 +199,17 @@ static unsigned int rt712_sdca_button_detect(struct rt712_sdca_priv *rt712) _end_btn_det_: /* Host is owner, so set back to device */ - if (owner == 0) + if (owner == 0) { /* set owner to device */ - regmap_write(rt712->regmap, - SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, - RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01); + if (rt712->version_id == RT712_VA) + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, + RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01); + else + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, + RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01); + } return btn_type; } @@ -415,8 +422,9 @@ static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712) switch (rt712->jd_src) { case RT712_JD1: - /* Set HP-JD source from JD1 */ - rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a); + /* Set HP-JD source from JD1, VB uses JD1 in default */ + if (rt712->version_id == RT712_VA) + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a); break; default: dev_warn(rt712->component->dev, "Wrong JD source\n"); @@ -592,20 +600,20 @@ static int rt712_sdca_set_gain_get(struct snd_kcontrol *kcontrol, static int rt712_sdca_set_fu0f_capture_ctl(struct rt712_sdca_priv *rt712) { int err; - unsigned int ch_l, ch_r; + unsigned int ch_01, ch_02; - ch_l = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00; - ch_r = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00; + ch_01 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_l_mute) ? 0x01 : 0x00; + ch_02 = (rt712->fu0f_dapm_mute || rt712->fu0f_mixer_r_mute) ? 0x01 : 0x00; err = regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, - RT712_SDCA_CTL_FU_MUTE, CH_L), ch_l); + RT712_SDCA_CTL_FU_MUTE, CH_01), ch_01); if (err < 0) return err; err = regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, - RT712_SDCA_CTL_FU_MUTE, CH_R), ch_r); + RT712_SDCA_CTL_FU_MUTE, CH_02), ch_02); if (err < 0) return err; @@ -649,28 +657,28 @@ static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0); static const struct snd_kcontrol_new rt712_sdca_controls[] = { SOC_DOUBLE_R_EXT_TLV("FU05 Playback Volume", - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_L), - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_R), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0, 0x57, 0, rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv), SOC_DOUBLE_EXT("FU0F Capture Switch", SND_SOC_NOPM, 0, 1, 1, 0, rt712_sdca_fu0f_capture_get, rt712_sdca_fu0f_capture_put), SOC_DOUBLE_R_EXT_TLV("FU0F Capture Volume", - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_L), - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_R), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0, 0x3f, 0, rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, mic_vol_tlv), SOC_DOUBLE_R_EXT_TLV("FU44 Boost Volume", - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_L), - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_R), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 8, 3, 0, rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, boost_vol_tlv), }; static const struct snd_kcontrol_new rt712_sdca_spk_controls[] = { SOC_DOUBLE_R_EXT_TLV("FU06 Playback Volume", - SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_L), - SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_R), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01), + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0, 0x57, 0, rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, out_vol_tlv), }; @@ -763,21 +771,21 @@ static int rt712_sdca_fu05_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMU: regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_L), + RT712_SDCA_CTL_FU_MUTE, CH_01), unmute); regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_R), + RT712_SDCA_CTL_FU_MUTE, CH_02), unmute); break; case SND_SOC_DAPM_PRE_PMD: regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_L), + RT712_SDCA_CTL_FU_MUTE, CH_01), mute); regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_R), + RT712_SDCA_CTL_FU_MUTE, CH_02), mute); break; } @@ -854,7 +862,7 @@ static int rt712_sdca_pde12_event(struct snd_soc_dapm_widget *w, return 0; } -static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w, +static int rt712_sdca_pde23_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = @@ -883,10 +891,13 @@ static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w, return 0; } -static const struct snd_kcontrol_new rt712_spk_sto_dac = - SOC_DAPM_DOUBLE_R("Switch", - SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_L), - SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_R), +static const struct snd_kcontrol_new rt712_spk_l_dac = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), + 0, 1, 1); +static const struct snd_kcontrol_new rt712_spk_r_dac = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0, 1, 1); static const struct snd_soc_dapm_widget rt712_sdca_dapm_widgets[] = { @@ -931,20 +942,26 @@ static const struct snd_soc_dapm_widget rt712_sdca_spk_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), /* Digital Interface */ - SND_SOC_DAPM_SWITCH("FU06", SND_SOC_NOPM, 0, 0, &rt712_spk_sto_dac), + SND_SOC_DAPM_PGA("FU06", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0, + rt712_sdca_pde23_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), /* Output */ - SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0, - rt712_sdca_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt712_spk_l_dac), + SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt712_spk_r_dac), SND_SOC_DAPM_OUTPUT("SPOL"), SND_SOC_DAPM_OUTPUT("SPOR"), }; static const struct snd_soc_dapm_route rt712_sdca_spk_dapm_routes[] = { - { "FU06", "Switch", "DP3RX" }, - { "CLASS D", NULL, "FU06" }, - { "SPOL", NULL, "CLASS D" }, - { "SPOR", NULL, "CLASS D" }, + { "FU06", NULL, "DP3RX" }, + { "FU06", NULL, "PDE 23" }, + { "OT23 L", "Switch", "FU06" }, + { "OT23 R", "Switch", "FU06" }, + { "SPOL", NULL, "OT23 L" }, + { "SPOR", NULL, "OT23 R" }, }; static int rt712_sdca_parse_dt(struct rt712_sdca_priv *rt712, struct device *dev) @@ -983,6 +1000,376 @@ static int rt712_sdca_probe(struct snd_soc_component *component) return 0; } +static int rt712_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int regvalue, ctl, i; + unsigned int adc_vol_flag = 0; + const unsigned int interval_offset = 0xc0; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt712->mbq_regmap, p->reg_base + i, ®value); + + if (!adc_vol_flag) /* boost gain */ + ctl = regvalue / 0x0a00; + else { /* ADC gain */ + if (adc_vol_flag) + ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset); + else + ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset); + } + + ucontrol->value.integer.value[i] = ctl; + } + + return 0; +} + +static int rt712_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + unsigned int gain_val[4]; + unsigned int i, adc_vol_flag = 0, changed = 0; + unsigned int regvalue[4]; + const unsigned int interval_offset = 0xc0; + int err; + + if (strstr(ucontrol->id.name, "FU1E Capture Volume")) + adc_vol_flag = 1; + + /* check all channels */ + for (i = 0; i < p->count; i++) { + regmap_read(rt712->mbq_regmap, p->reg_base + i, ®value[i]); + + gain_val[i] = ucontrol->value.integer.value[i]; + if (gain_val[i] > p->max) + gain_val[i] = p->max; + + if (!adc_vol_flag) /* boost gain */ + gain_val[i] = gain_val[i] * 0x0a00; + else { /* ADC gain */ + gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset); + gain_val[i] &= 0xffff; + } + + if (regvalue[i] != gain_val[i]) + changed = 1; + } + + if (!changed) + return 0; + + for (i = 0; i < p->count; i++) { + err = regmap_write(rt712->mbq_regmap, p->reg_base + i, gain_val[i]); + if (err < 0) + dev_err(&rt712->slave->dev, "0x%08x can't be set\n", p->reg_base + i); + } + + return changed; +} + +static int rt712_sdca_set_fu1e_capture_ctl(struct rt712_sdca_priv *rt712) +{ + int err, i; + unsigned int ch_mute; + + for (i = 0; i < ARRAY_SIZE(rt712->fu1e_mixer_mute); i++) { + ch_mute = (rt712->fu1e_dapm_mute || rt712->fu1e_mixer_mute[i]) ? 0x01 : 0x00; + err = regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, + RT712_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute); + if (err < 0) + return err; + } + + return 0; +} + +static int rt712_sdca_dmic_fu1e_capture_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + unsigned int i; + + for (i = 0; i < p->count; i++) + ucontrol->value.integer.value[i] = !rt712->fu1e_mixer_mute[i]; + + return 0; +} + +static int rt712_sdca_dmic_fu1e_capture_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + int err, changed = 0, i; + + for (i = 0; i < p->count; i++) { + if (rt712->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i]) + changed = 1; + rt712->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i]; + } + + err = rt712_sdca_set_fu1e_capture_ctl(rt712); + if (err < 0) + return err; + + return changed; +} + +static int rt712_sdca_fu_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct rt712_dmic_kctrl_priv *p = + (struct rt712_dmic_kctrl_priv *)kcontrol->private_value; + + if (p->max == 1) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = p->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = p->max; + return 0; +} + +#define RT712_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \ + ((unsigned long)&(struct rt712_dmic_kctrl_priv) \ + {.reg_base = xreg_base, .count = xcount, .max = xmax, \ + .invert = xinvert}) + +#define RT712_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = rt712_sdca_fu_info, \ + .get = rt712_sdca_dmic_fu1e_capture_get, \ + .put = rt712_sdca_dmic_fu1e_capture_put, \ + .private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)} + +#define RT712_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\ + xhandler_put, xcount, xmax, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = rt712_sdca_fu_info, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) } + +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); +static const DECLARE_TLV_DB_SCALE(dmic_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt712_sdca_dmic_snd_controls[] = { + RT712_SDCA_FU_CTRL("FU1E Capture Switch", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), + 1, 1, 4), + RT712_SDCA_EXT_TLV("FU1E Capture Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01), + rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 0x3f, in_vol_tlv), + RT712_SDCA_EXT_TLV("FU15 Boost Volume", + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), + rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 3, dmic_vol_tlv), +}; + +static int rt712_sdca_dmic_mux_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + unsigned int val = 0, mask_sft; + + if (strstr(ucontrol->id.name, "ADC 0A Mux")) + mask_sft = 0; + else if (strstr(ucontrol->id.name, "ADC 0B Mux")) + mask_sft = 4; + else + return -EINVAL; + + rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL, + RT712_HDA_LEGACY_MUX_CTL0, &val); + + ucontrol->value.enumerated.item[0] = (((val >> mask_sft) & 0xf) == 0x4) ? 0 : 1; + + return 0; +} + +static int rt712_sdca_dmic_mux_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_dapm_kcontrol_component(kcontrol); + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + unsigned int val, val2 = 0, change, mask_sft; + + if (item[0] >= e->items) + return -EINVAL; + + if (strstr(ucontrol->id.name, "ADC 0A Mux")) + mask_sft = 0; + else if (strstr(ucontrol->id.name, "ADC 0B Mux")) + mask_sft = 4; + else + return -EINVAL; + + val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; + + rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL, + RT712_HDA_LEGACY_MUX_CTL0, &val2); + val2 = ((0xf << mask_sft) & val2) >> mask_sft; + + if (val == 0) + val = 0x4; + else if (val >= 1) + val = 0xe; + + if (val == val2) + change = 0; + else + change = 1; + + if (change) + rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL, + RT712_HDA_LEGACY_MUX_CTL0, 0xf << mask_sft, + val << mask_sft); + + snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL); + + return change; +} + +static const char * const adc_dmic_mux_text[] = { + "DMIC1", + "DMIC2", +}; + +static SOC_ENUM_SINGLE_DECL( + rt712_adc0a_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text); + +static SOC_ENUM_SINGLE_DECL( + rt712_adc0b_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text); + +static const struct snd_kcontrol_new rt712_sdca_dmic_adc0a_mux = + SOC_DAPM_ENUM_EXT("ADC 0A Mux", rt712_adc0a_enum, + rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put); + +static const struct snd_kcontrol_new rt712_sdca_dmic_adc0b_mux = + SOC_DAPM_ENUM_EXT("ADC 0B Mux", rt712_adc0b_enum, + rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put); + +static int rt712_sdca_dmic_fu1e_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + rt712->fu1e_dapm_mute = false; + rt712_sdca_set_fu1e_capture_ctl(rt712); + break; + case SND_SOC_DAPM_PRE_PMD: + rt712->fu1e_dapm_mute = true; + rt712_sdca_set_fu1e_capture_ctl(rt712); + break; + } + return 0; +} + +static int rt712_sdca_dmic_pde11_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + unsigned char ps0 = 0x0, ps3 = 0x3; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11, + RT712_SDCA_CTL_REQ_POWER_STATE, 0), + ps0); + break; + case SND_SOC_DAPM_PRE_PMD: + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11, + RT712_SDCA_CTL_REQ_POWER_STATE, 0), + ps3); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget rt712_sdca_dmic_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + + SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0, + rt712_sdca_dmic_pde11_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_ADC_E("FU 1E", NULL, SND_SOC_NOPM, 0, 0, + rt712_sdca_dmic_fu1e_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_MUX("ADC 0A Mux", SND_SOC_NOPM, 0, 0, + &rt712_sdca_dmic_adc0a_mux), + SND_SOC_DAPM_MUX("ADC 0B Mux", SND_SOC_NOPM, 0, 0, + &rt712_sdca_dmic_adc0b_mux), + + SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_dapm_route rt712_sdca_dmic_audio_map[] = { + {"DP8TX", NULL, "FU 1E"}, + + {"FU 1E", NULL, "PDE 11"}, + {"FU 1E", NULL, "ADC 0A Mux"}, + {"FU 1E", NULL, "ADC 0B Mux"}, + {"ADC 0A Mux", "DMIC1", "DMIC1"}, + {"ADC 0A Mux", "DMIC2", "DMIC2"}, + {"ADC 0B Mux", "DMIC1", "DMIC1"}, + {"ADC 0B Mux", "DMIC2", "DMIC2"}, +}; + +static int rt712_sdca_dmic_probe(struct snd_soc_component *component) +{ + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + int ret; + + rt712->dmic_component = component; + + if (!rt712->first_hw_init) + return 0; + + ret = pm_runtime_resume(component->dev); + if (ret < 0 && ret != -EACCES) + return ret; + + return 0; +} + static const struct snd_soc_component_driver soc_sdca_dev_rt712 = { .probe = rt712_sdca_probe, .controls = rt712_sdca_controls, @@ -995,6 +1382,20 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt712 = { .endianness = 1, }; +static const struct snd_soc_component_driver soc_sdca_dev_rt712_dmic = { + .probe = rt712_sdca_dmic_probe, + .controls = rt712_sdca_dmic_snd_controls, + .num_controls = ARRAY_SIZE(rt712_sdca_dmic_snd_controls), + .dapm_widgets = rt712_sdca_dmic_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt712_sdca_dmic_dapm_widgets), + .dapm_routes = rt712_sdca_dmic_audio_map, + .num_dapm_routes = ARRAY_SIZE(rt712_sdca_dmic_audio_map), + .endianness = 1, +#ifdef CONFIG_DEBUG_FS + .debugfs_prefix = "dmic", +#endif +}; + static int rt712_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, int direction) { @@ -1022,7 +1423,7 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, int retval, port, num_channels; unsigned int sampling_rate; - dev_dbg(dai->dev, "%s %s", __func__, dai->name); + dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id); sdw_stream = snd_soc_dai_get_dma_data(dai, substream); if (!sdw_stream) @@ -1031,6 +1432,10 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, if (!rt712->slave) return -EINVAL; + /* VA doesn't support AIF3 */ + if (dai->id == RT712_AIF3 && rt712->version_id == RT712_VA) + return -EINVAL; + /* SoundWire specific configuration */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { direction = SDW_DATA_DIR_RX; @@ -1044,6 +1449,8 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, direction = SDW_DATA_DIR_TX; if (dai->id == RT712_AIF1) port = 4; + else if (dai->id == RT712_AIF3) + port = 8; else return -EINVAL; } @@ -1105,6 +1512,14 @@ static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream, SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), sampling_rate); break; + case RT712_AIF3: + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + sampling_rate); + break; default: dev_err(component->dev, "%s: Wrong DAI id\n", __func__); return -EINVAL; @@ -1174,6 +1589,21 @@ static struct snd_soc_dai_driver rt712_sdca_dai[] = { } }; +static struct snd_soc_dai_driver rt712_sdca_dmic_dai[] = { + { + .name = "rt712-sdca-aif3", + .id = RT712_AIF3, + .capture = { + .stream_name = "DP8 Capture", + .channels_min = 1, + .channels_max = 4, + .rates = RT712_STEREO_RATES, + .formats = RT712_FORMATS, + }, + .ops = &rt712_sdca_ops, + } +}; + int rt712_sdca_init(struct device *dev, struct regmap *regmap, struct regmap *mbq_regmap, struct sdw_slave *slave) { @@ -1206,6 +1636,9 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, rt712->first_hw_init = false; rt712->fu0f_dapm_mute = true; rt712->fu0f_mixer_l_mute = rt712->fu0f_mixer_r_mute = true; + rt712->fu1e_dapm_mute = true; + rt712->fu1e_mixer_mute[0] = rt712->fu1e_mixer_mute[1] = + rt712->fu1e_mixer_mute[2] = rt712->fu1e_mixer_mute[3] = true; /* JD source uses JD1 in default */ rt712->jd_src = RT712_JD1; @@ -1239,35 +1672,11 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, return 0; } -int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) +static void rt712_sdca_va_io_init(struct rt712_sdca_priv *rt712) { - struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev); int ret = 0; - unsigned int val, hibernation_flag; - - rt712->disable_irq = false; - - if (rt712->hw_init) - return 0; - - regcache_cache_only(rt712->regmap, false); - regcache_cache_only(rt712->mbq_regmap, false); - if (rt712->first_hw_init) { - regcache_cache_bypass(rt712->regmap, true); - regcache_cache_bypass(rt712->mbq_regmap, true); - } else { - /* - * PM runtime status is marked as 'active' only when a Slave reports as Attached - */ - - /* update count of parent 'active' children */ - pm_runtime_set_active(&slave->dev); - } - - pm_runtime_get_noresume(&slave->dev); - - rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val); - rt712->hw_id = (val & 0xf000) >> 12; + unsigned int hibernation_flag; + struct device *dev = &rt712->slave->dev; rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81); rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0); @@ -1307,6 +1716,131 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) regmap_write(rt712->regmap, SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04); } +} + +static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712) +{ + int ret = 0; + unsigned int jack_func_status, mic_func_status, amp_func_status; + struct device *dev = &rt712->slave->dev; + + regmap_read(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &jack_func_status); + regmap_read(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &mic_func_status); + regmap_read(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &_func_status); + dev_dbg(dev, "%s jack/mic/amp func_status=0x%x, 0x%x, 0x%x\n", + __func__, jack_func_status, mic_func_status, amp_func_status); + + /* DMIC */ + if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) { + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_IT_FLOAT_CTL, 0x1526); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_CH12_FLOAT_CTL, 0x0304); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL, 0x1f1e); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0B_FU_CH12_FLOAT_CTL, 0x0304); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_HDA_LEGACY_CONFIG_CTL0, 0x8010); + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT11, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01); + rt712_sdca_index_write(rt712, RT712_ULTRA_SOUND_DET, RT712_ULTRA_SOUND_DETECTOR6, 0x3200); + regmap_write(rt712->regmap, RT712_RC_CAL, 0x23); + + /* clear flag */ + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), + FUNCTION_NEEDS_INITIALIZATION); + } + + /* Jack */ + if ((jack_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) { + rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_SEL_VEE2_HP_CTL1, 0x042a); + rt712_sdca_index_write(rt712, RT712_CHARGE_PUMP, RT712_HP_DET_CTL3, 0x1fff); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec67); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0); + rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL1, 0x0000); + rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL2, 0x0000); + regmap_write(rt712->regmap, RT712_RC_CAL, 0x23); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_JD_CTL1, 0x2802); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL6, 0xf215); + + /* calibration */ + ret = rt712_sdca_calibration(rt712); + if (ret < 0) + dev_err(dev, "%s, calibration failed!\n", __func__); + + rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL, RT712_MIXER_CTL1, 0x3000, 0x0000); + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_IT09, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_MISC_CTL_FOR_UAJ, 0x0003); + + /* clear flag */ + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), + FUNCTION_NEEDS_INITIALIZATION); + } + + /* SPK */ + if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) { + if (rt712->hw_id != RT712_DEV_ID_713) { + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec63); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL1, 0xfff5); + rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_EAPD_CTL, 0x0002); + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04); + } + /* clear flag */ + regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), + FUNCTION_NEEDS_INITIALIZATION); + } +} + +int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) +{ + struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev); + int ret = 0; + unsigned int val; + struct sdw_slave_prop *prop = &slave->prop; + + rt712->disable_irq = false; + + if (rt712->hw_init) + return 0; + + regcache_cache_only(rt712->regmap, false); + regcache_cache_only(rt712->mbq_regmap, false); + if (rt712->first_hw_init) { + regcache_cache_bypass(rt712->regmap, true); + regcache_cache_bypass(rt712->mbq_regmap, true); + } else { + /* + * PM runtime status is marked as 'active' only when a Slave reports as Attached + */ + + /* update count of parent 'active' children */ + pm_runtime_set_active(&slave->dev); + } + + pm_runtime_get_noresume(&slave->dev); + + rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val); + rt712->hw_id = (val & 0xf000) >> 12; + rt712->version_id = (val & 0x0f00) >> 8; + dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id); + + if (rt712->version_id == RT712_VA) + rt712_sdca_va_io_init(rt712); + else { + /* multilanes and DMIC are supported by rt712vb */ + ret = devm_snd_soc_register_component(dev, + &soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai)); + if (ret < 0) + return ret; + + prop->lane_control_support = true; + rt712_sdca_vb_io_init(rt712); + } /* * if set_jack callback occurred early than io_init, @@ -1315,8 +1849,7 @@ int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt712->hs_jack) rt712_sdca_jack_init(rt712); - if (!hibernation_flag) - rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001); + rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001); if (rt712->first_hw_init) { regcache_cache_bypass(rt712->regmap, false); diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h index ff79e03118ce..2169f2f726b9 100644 --- a/sound/soc/codecs/rt712-sdca.h +++ b/sound/soc/codecs/rt712-sdca.h @@ -19,6 +19,7 @@ struct rt712_sdca_priv { struct regmap *regmap; struct regmap *mbq_regmap; struct snd_soc_component *component; + struct snd_soc_component *dmic_component; struct sdw_slave *slave; struct sdw_bus_params params; bool hw_init; @@ -34,13 +35,31 @@ struct rt712_sdca_priv { unsigned int scp_sdca_stat1; unsigned int scp_sdca_stat2; unsigned int hw_id; + unsigned int version_id; bool fu0f_dapm_mute; bool fu0f_mixer_l_mute; bool fu0f_mixer_r_mute; + bool fu1e_dapm_mute; + bool fu1e_mixer_mute[4]; }; +struct rt712_dmic_kctrl_priv { + unsigned int reg_base; + unsigned int count; + unsigned int max; + unsigned int invert; +}; + +/* SDCA (Channel) */ +#define CH_01 0x01 +#define CH_02 0x02 +#define CH_03 0x03 +#define CH_04 0x04 + /* NID */ #define RT712_VENDOR_REG 0x20 +#define RT712_EQ_CTRL 0x53 +#define RT712_CHARGE_PUMP 0x57 #define RT712_VENDOR_CALI 0x58 #define RT712_ULTRA_SOUND_DET 0x59 #define RT712_VENDOR_IMS_DRE 0x5b @@ -50,9 +69,13 @@ struct rt712_sdca_priv { /* Index (NID:20h) */ #define RT712_JD_PRODUCT_NUM 0x00 #define RT712_ANALOG_BIAS_CTL3 0x04 +#define RT712_JD_CTL1 0x09 +#define RT712_IO_CTL 0x0c #define RT712_LDO2_3_CTL1 0x0e #define RT712_PARA_VERB_CTL 0x1a #define RT712_CC_DET1 0x24 +#define RT712_CLASSD_AMP_CTL1 0x37 +#define RT712_CLASSD_AMP_CTL6 0x3c #define RT712_COMBO_JACK_AUTO_CTL1 0x45 #define RT712_COMBO_JACK_AUTO_CTL2 0x46 #define RT712_COMBO_JACK_AUTO_CTL3 0x47 @@ -61,6 +84,9 @@ struct rt712_sdca_priv { #define RT712_SW_CONFIG1 0x8a #define RT712_SW_CONFIG2 0x8b +/* Index (NID:57h) */ +#define RT712_HP_DET_CTL3 0x0c + /* Index (NID:58h) */ #define RT712_DAC_DC_CALI_CTL1 0x00 #define RT712_DAC_DC_CALI_CTL2 0x01 @@ -71,6 +97,7 @@ struct rt712_sdca_priv { /* Index (NID:5bh) */ #define RT712_IMS_DIGITAL_CTL1 0x00 #define RT712_IMS_DIGITAL_CTL5 0x05 +#define RT712_SEL_VEE2_HP_CTL1 0x23 #define RT712_HP_DETECT_RLDET_CTL1 0x29 #define RT712_HP_DETECT_RLDET_CTL2 0x2a @@ -109,6 +136,11 @@ struct rt712_sdca_priv { #define RT712_UMP_HID_CTL6 0x66 #define RT712_UMP_HID_CTL7 0x67 #define RT712_UMP_HID_CTL8 0x68 +#define RT712_MISC_CTL_FOR_UAJ 0x72 +#define RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL 0xa2 +#define RT712_DMIC2_FU_IT_FLOAT_CTL 0xa6 +#define RT712_ADC0B_FU_CH12_FLOAT_CTL 0xb0 +#define RT712_DMIC2_FU_CH12_FLOAT_CTL 0xb1 /* Parameter & Verb control 01 (0x1a)(NID:20h) */ #define RT712_HIDDEN_REG_SW_RESET (0x1 << 14) @@ -139,6 +171,7 @@ struct rt712_sdca_priv { #define FUNC_NUM_AMP 0x04 /* RT712 SDCA entity */ +#define RT712_SDCA_ENT0 0x00 #define RT712_SDCA_ENT_HID01 0x01 #define RT712_SDCA_ENT_GE49 0x49 #define RT712_SDCA_ENT_USER_FU05 0x05 @@ -157,6 +190,7 @@ struct rt712_sdca_priv { #define RT712_SDCA_ENT_CS1C 0x1c #define RT712_SDCA_ENT_CS31 0x31 #define RT712_SDCA_ENT_OT23 0x42 +#define RT712_SDCA_ENT_IT11 0x26 #define RT712_SDCA_ENT_IT26 0x26 #define RT712_SDCA_ENT_IT09 0x09 #define RT712_SDCA_ENT_PLATFORM_FU15 0x15 @@ -175,10 +209,12 @@ struct rt712_sdca_priv { #define RT712_SDCA_CTL_REQ_POWER_STATE 0x01 #define RT712_SDCA_CTL_VENDOR_DEF 0x30 #define RT712_SDCA_CTL_FU_CH_GAIN 0x0b +#define RT712_SDCA_CTL_FUNC_STATUS 0x10 -/* RT712 SDCA channel */ -#define CH_L 0x01 -#define CH_R 0x02 +/* Function_Status */ +#define FUNCTION_NEEDS_INITIALIZATION BIT(5) +#define FUNCTION_HAS_BEEN_RESET BIT(6) +#define FUNCTION_BUSY BIT(7) /* sample frequency index */ #define RT712_SDCA_RATE_16000HZ 0x04 @@ -191,6 +227,7 @@ struct rt712_sdca_priv { enum { RT712_AIF1, RT712_AIF2, + RT712_AIF3, }; enum rt712_sdca_jd_src { @@ -207,6 +244,11 @@ enum rt712_sdca_hw_id { #define RT712_PART_ID_713 0x713 +enum rt712_sdca_version { + RT712_VA, + RT712_VB, +}; + int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave); int rt712_sdca_init(struct device *dev, struct regmap *regmap, struct regmap *mbq_regmap, struct sdw_slave *slave); diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 7b981aa8690a..acf7d92d21e6 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -143,6 +143,8 @@ static int graph_link_init(struct simple_util_priv *priv, struct device_node *port_codec = ep_to_port(ep_codec); struct device_node *ports_cpu = port_to_ports(port_cpu); struct device_node *ports_codec = port_to_ports(port_codec); + enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT; + enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT; bool playback_only = 0, capture_only = 0; int ret; @@ -165,9 +167,20 @@ static int graph_link_init(struct simple_util_priv *priv, of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs); + graph_util_parse_trigger_order(priv, top, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ports_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ports_codec, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ep_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ep_codec, &trigger_start, &trigger_stop); + dai_link->playback_only = playback_only; dai_link->capture_only = capture_only; + dai_link->trigger_start = trigger_start; + dai_link->trigger_stop = trigger_stop; + dai_link->init = simple_util_dai_init; dai_link->ops = &graph_ops; if (priv->ops) diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index be5a4ebfddd4..93d9d045587b 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -759,6 +759,8 @@ static void graph_link_init(struct simple_util_priv *priv, struct device_node *ports_cpu, *ports_codec; unsigned int daifmt = 0, daiclk = 0; bool playback_only = 0, capture_only = 0; + enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT; + enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT; unsigned int bit_frame = 0; of_node_get(port_cpu); @@ -806,6 +808,14 @@ static void graph_link_init(struct simple_util_priv *priv, of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs); + graph_util_parse_trigger_order(priv, lnk, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ports_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ports_codec, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ep_cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, ep_codec, &trigger_start, &trigger_stop); + /* * convert bit_frame * We need to flip clock_provider if it was CPU node, @@ -818,6 +828,9 @@ static void graph_link_init(struct simple_util_priv *priv, dai_link->playback_only = playback_only; dai_link->capture_only = capture_only; + dai_link->trigger_start = trigger_start; + dai_link->trigger_stop = trigger_stop; + dai_link->dai_fmt = daifmt | daiclk; dai_link->init = simple_util_dai_init; dai_link->ops = &graph_ops; diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index dcd0569157ce..a18de86b3c88 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -4,6 +4,7 @@ // // Copyright (c) 2016 Kuninori Morimoto <[email protected]> +#include <dt-bindings/sound/audio-graph.h> #include <linux/clk.h> #include <linux/gpio/consumer.h> #include <linux/module.h> @@ -1156,6 +1157,76 @@ void graph_util_parse_link_direction(struct device_node *np, } EXPORT_SYMBOL_GPL(graph_util_parse_link_direction); +static enum snd_soc_trigger_order +__graph_util_parse_trigger_order(struct simple_util_priv *priv, + struct device_node *np, + const char *prop) +{ + u32 val[SND_SOC_TRIGGER_SIZE]; + int ret; + + ret = of_property_read_u32_array(np, prop, val, SND_SOC_TRIGGER_SIZE); + if (ret == 0) { + struct device *dev = simple_priv_to_dev(priv); + u32 order = (val[0] << 8) + + (val[1] << 4) + + (val[2]); + + switch (order) { + case (SND_SOC_TRIGGER_LINK << 8) + + (SND_SOC_TRIGGER_COMPONENT << 4) + + (SND_SOC_TRIGGER_DAI): + return SND_SOC_TRIGGER_ORDER_DEFAULT; + + case (SND_SOC_TRIGGER_LINK << 8) + + (SND_SOC_TRIGGER_DAI << 4) + + (SND_SOC_TRIGGER_COMPONENT): + return SND_SOC_TRIGGER_ORDER_LDC; + + default: + dev_err(dev, "unsupported trigger order [0x%x]\n", order); + } + } + + /* SND_SOC_TRIGGER_ORDER_MAX means error */ + return SND_SOC_TRIGGER_ORDER_MAX; +} + +void graph_util_parse_trigger_order(struct simple_util_priv *priv, + struct device_node *np, + enum snd_soc_trigger_order *trigger_start, + enum snd_soc_trigger_order *trigger_stop) +{ + static enum snd_soc_trigger_order order; + + /* + * We can use it like below + * + * #include <dt-bindings/sound/audio-graph.h> + * + * link-trigger-order = <SND_SOC_TRIGGER_LINK + * SND_SOC_TRIGGER_COMPONENT + * SND_SOC_TRIGGER_DAI>; + */ + + order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order"); + if (order < SND_SOC_TRIGGER_ORDER_MAX) { + *trigger_start = order; + *trigger_stop = order; + } + + order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-start"); + if (order < SND_SOC_TRIGGER_ORDER_MAX) + *trigger_start = order; + + order = __graph_util_parse_trigger_order(priv, np, "link-trigger-order-stop"); + if (order < SND_SOC_TRIGGER_ORDER_MAX) + *trigger_stop = order; + + return; +} +EXPORT_SYMBOL_GPL(graph_util_parse_trigger_order); + /* Module information */ MODULE_AUTHOR("Kuninori Morimoto <[email protected]>"); MODULE_DESCRIPTION("ALSA SoC Simple Card Utils"); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 2de5e6efe947..edbb6322e9be 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -176,6 +176,8 @@ static int simple_link_init(struct simple_util_priv *priv, struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); struct device_node *node = of_get_parent(cpu); + enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT; + enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT; bool playback_only = 0, capture_only = 0; int ret; @@ -198,9 +200,17 @@ static int simple_link_init(struct simple_util_priv *priv, of_property_read_u32(codec, "mclk-fs", &dai_props->mclk_fs); of_property_read_u32(codec, PREFIX "mclk-fs", &dai_props->mclk_fs); + graph_util_parse_trigger_order(priv, top, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, node, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, cpu, &trigger_start, &trigger_stop); + graph_util_parse_trigger_order(priv, codec, &trigger_start, &trigger_stop); + dai_link->playback_only = playback_only; dai_link->capture_only = capture_only; + dai_link->trigger_start = trigger_start; + dai_link->trigger_stop = trigger_stop; + dai_link->init = simple_util_dai_init; dai_link->ops = &simple_ops; diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index b0f3e02cb043..5a47f661e0c6 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -1166,9 +1166,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm"); + if (!res) + return -EINVAL; drvdata->rxtx_cdc_dma_lpm_buf = res->start; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm"); + if (!res) + return -EINVAL; drvdata->va_cdc_dma_lpm_buf = res->start; } |