18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// rt700.c -- rt700 ALSA SoC audio driver 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright(c) 2019 Realtek Semiconductor Corp. 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 158c2ecf20Sopenharmony_ci#include <linux/pm.h> 168c2ecf20Sopenharmony_ci#include <linux/soundwire/sdw.h> 178c2ecf20Sopenharmony_ci#include <linux/regmap.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <sound/core.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm.h> 218c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 228c2ecf20Sopenharmony_ci#include <sound/soc.h> 238c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h> 248c2ecf20Sopenharmony_ci#include <sound/initval.h> 258c2ecf20Sopenharmony_ci#include <sound/tlv.h> 268c2ecf20Sopenharmony_ci#include <sound/hda_verbs.h> 278c2ecf20Sopenharmony_ci#include <sound/jack.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "rt700.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int rt700_index_write(struct regmap *regmap, 328c2ecf20Sopenharmony_ci unsigned int reg, unsigned int value) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci int ret; 358c2ecf20Sopenharmony_ci unsigned int addr = (RT700_PRIV_INDEX_W_H << 8) | reg; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci ret = regmap_write(regmap, addr, value); 388c2ecf20Sopenharmony_ci if (ret < 0) 398c2ecf20Sopenharmony_ci pr_err("Failed to set private value: %06x <= %04x ret=%d\n", 408c2ecf20Sopenharmony_ci addr, value, ret); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return ret; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic int rt700_index_read(struct regmap *regmap, 468c2ecf20Sopenharmony_ci unsigned int reg, unsigned int *value) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci int ret; 498c2ecf20Sopenharmony_ci unsigned int addr = (RT700_PRIV_INDEX_W_H << 8) | reg; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci *value = 0; 528c2ecf20Sopenharmony_ci ret = regmap_read(regmap, addr, value); 538c2ecf20Sopenharmony_ci if (ret < 0) 548c2ecf20Sopenharmony_ci pr_err("Failed to get private value: %06x => %04x ret=%d\n", 558c2ecf20Sopenharmony_ci addr, *value, ret); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return ret; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic unsigned int rt700_button_detect(struct rt700_priv *rt700) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci unsigned int btn_type = 0, val80, val81; 638c2ecf20Sopenharmony_ci int ret; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci ret = rt700_index_read(rt700->regmap, RT700_IRQ_FLAG_TABLE1, &val80); 668c2ecf20Sopenharmony_ci if (ret < 0) 678c2ecf20Sopenharmony_ci goto read_error; 688c2ecf20Sopenharmony_ci ret = rt700_index_read(rt700->regmap, RT700_IRQ_FLAG_TABLE2, &val81); 698c2ecf20Sopenharmony_ci if (ret < 0) 708c2ecf20Sopenharmony_ci goto read_error; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci val80 &= 0x0381; 738c2ecf20Sopenharmony_ci val81 &= 0xff00; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci switch (val80) { 768c2ecf20Sopenharmony_ci case 0x0200: 778c2ecf20Sopenharmony_ci case 0x0100: 788c2ecf20Sopenharmony_ci case 0x0080: 798c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_0; 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci case 0x0001: 828c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_3; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci switch (val81) { 868c2ecf20Sopenharmony_ci case 0x8000: 878c2ecf20Sopenharmony_ci case 0x4000: 888c2ecf20Sopenharmony_ci case 0x2000: 898c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_1; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci case 0x1000: 928c2ecf20Sopenharmony_ci case 0x0800: 938c2ecf20Sopenharmony_ci case 0x0400: 948c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_2; 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci case 0x0200: 978c2ecf20Sopenharmony_ci case 0x0100: 988c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_3; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ciread_error: 1028c2ecf20Sopenharmony_ci return btn_type; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int rt700_headset_detect(struct rt700_priv *rt700) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci unsigned int buf, loop = 0; 1088c2ecf20Sopenharmony_ci int ret; 1098c2ecf20Sopenharmony_ci unsigned int jack_status = 0, reg; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci ret = rt700_index_read(rt700->regmap, 1128c2ecf20Sopenharmony_ci RT700_COMBO_JACK_AUTO_CTL2, &buf); 1138c2ecf20Sopenharmony_ci if (ret < 0) 1148c2ecf20Sopenharmony_ci goto io_error; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci while (loop < 500 && 1178c2ecf20Sopenharmony_ci (buf & RT700_COMBOJACK_AUTO_DET_STATUS) == 0) { 1188c2ecf20Sopenharmony_ci loop++; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci usleep_range(9000, 10000); 1218c2ecf20Sopenharmony_ci ret = rt700_index_read(rt700->regmap, 1228c2ecf20Sopenharmony_ci RT700_COMBO_JACK_AUTO_CTL2, &buf); 1238c2ecf20Sopenharmony_ci if (ret < 0) 1248c2ecf20Sopenharmony_ci goto io_error; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT; 1278c2ecf20Sopenharmony_ci ret = regmap_read(rt700->regmap, reg, &jack_status); 1288c2ecf20Sopenharmony_ci if ((jack_status & (1 << 31)) == 0) 1298c2ecf20Sopenharmony_ci goto remove_error; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (loop >= 500) 1338c2ecf20Sopenharmony_ci goto to_error; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (buf & RT700_COMBOJACK_AUTO_DET_TRS) 1368c2ecf20Sopenharmony_ci rt700->jack_type = SND_JACK_HEADPHONE; 1378c2ecf20Sopenharmony_ci else if ((buf & RT700_COMBOJACK_AUTO_DET_CTIA) || 1388c2ecf20Sopenharmony_ci (buf & RT700_COMBOJACK_AUTO_DET_OMTP)) 1398c2ecf20Sopenharmony_ci rt700->jack_type = SND_JACK_HEADSET; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cito_error: 1448c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 1458c2ecf20Sopenharmony_ci pr_err_ratelimited("Time-out error in %s\n", __func__); 1468c2ecf20Sopenharmony_ci return ret; 1478c2ecf20Sopenharmony_ciio_error: 1488c2ecf20Sopenharmony_ci pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 1498c2ecf20Sopenharmony_ci return ret; 1508c2ecf20Sopenharmony_ciremove_error: 1518c2ecf20Sopenharmony_ci pr_err_ratelimited("Jack removal in %s\n", __func__); 1528c2ecf20Sopenharmony_ci return -ENODEV; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void rt700_jack_detect_handler(struct work_struct *work) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = 1588c2ecf20Sopenharmony_ci container_of(work, struct rt700_priv, jack_detect_work.work); 1598c2ecf20Sopenharmony_ci int btn_type = 0, ret; 1608c2ecf20Sopenharmony_ci unsigned int jack_status = 0, reg; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!rt700->hs_jack) 1638c2ecf20Sopenharmony_ci return; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (!rt700->component->card->instantiated) 1668c2ecf20Sopenharmony_ci return; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT; 1698c2ecf20Sopenharmony_ci ret = regmap_read(rt700->regmap, reg, &jack_status); 1708c2ecf20Sopenharmony_ci if (ret < 0) 1718c2ecf20Sopenharmony_ci goto io_error; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* pin attached */ 1748c2ecf20Sopenharmony_ci if (jack_status & (1 << 31)) { 1758c2ecf20Sopenharmony_ci /* jack in */ 1768c2ecf20Sopenharmony_ci if (rt700->jack_type == 0) { 1778c2ecf20Sopenharmony_ci ret = rt700_headset_detect(rt700); 1788c2ecf20Sopenharmony_ci if (ret < 0) 1798c2ecf20Sopenharmony_ci return; 1808c2ecf20Sopenharmony_ci if (rt700->jack_type == SND_JACK_HEADSET) 1818c2ecf20Sopenharmony_ci btn_type = rt700_button_detect(rt700); 1828c2ecf20Sopenharmony_ci } else if (rt700->jack_type == SND_JACK_HEADSET) { 1838c2ecf20Sopenharmony_ci /* jack is already in, report button event */ 1848c2ecf20Sopenharmony_ci btn_type = rt700_button_detect(rt700); 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci } else { 1878c2ecf20Sopenharmony_ci /* jack out */ 1888c2ecf20Sopenharmony_ci rt700->jack_type = 0; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci dev_dbg(&rt700->slave->dev, 1928c2ecf20Sopenharmony_ci "in %s, jack_type=0x%x\n", __func__, rt700->jack_type); 1938c2ecf20Sopenharmony_ci dev_dbg(&rt700->slave->dev, 1948c2ecf20Sopenharmony_ci "in %s, btn_type=0x%x\n", __func__, btn_type); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci snd_soc_jack_report(rt700->hs_jack, rt700->jack_type | btn_type, 1978c2ecf20Sopenharmony_ci SND_JACK_HEADSET | 1988c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 1998c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (btn_type) { 2028c2ecf20Sopenharmony_ci /* button released */ 2038c2ecf20Sopenharmony_ci snd_soc_jack_report(rt700->hs_jack, rt700->jack_type, 2048c2ecf20Sopenharmony_ci SND_JACK_HEADSET | 2058c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 2068c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 2098c2ecf20Sopenharmony_ci &rt700->jack_btn_check_work, msecs_to_jiffies(200)); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ciio_error: 2158c2ecf20Sopenharmony_ci pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic void rt700_btn_check_handler(struct work_struct *work) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = container_of(work, struct rt700_priv, 2218c2ecf20Sopenharmony_ci jack_btn_check_work.work); 2228c2ecf20Sopenharmony_ci int btn_type = 0, ret; 2238c2ecf20Sopenharmony_ci unsigned int jack_status = 0, reg; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT; 2268c2ecf20Sopenharmony_ci ret = regmap_read(rt700->regmap, reg, &jack_status); 2278c2ecf20Sopenharmony_ci if (ret < 0) 2288c2ecf20Sopenharmony_ci goto io_error; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* pin attached */ 2318c2ecf20Sopenharmony_ci if (jack_status & (1 << 31)) { 2328c2ecf20Sopenharmony_ci if (rt700->jack_type == SND_JACK_HEADSET) { 2338c2ecf20Sopenharmony_ci /* jack is already in, report button event */ 2348c2ecf20Sopenharmony_ci btn_type = rt700_button_detect(rt700); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } else { 2378c2ecf20Sopenharmony_ci rt700->jack_type = 0; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* cbj comparator */ 2418c2ecf20Sopenharmony_ci ret = rt700_index_read(rt700->regmap, RT700_COMBO_JACK_AUTO_CTL2, ®); 2428c2ecf20Sopenharmony_ci if (ret < 0) 2438c2ecf20Sopenharmony_ci goto io_error; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if ((reg & 0xf0) == 0xf0) 2468c2ecf20Sopenharmony_ci btn_type = 0; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci dev_dbg(&rt700->slave->dev, 2498c2ecf20Sopenharmony_ci "%s, btn_type=0x%x\n", __func__, btn_type); 2508c2ecf20Sopenharmony_ci snd_soc_jack_report(rt700->hs_jack, rt700->jack_type | btn_type, 2518c2ecf20Sopenharmony_ci SND_JACK_HEADSET | 2528c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 2538c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (btn_type) { 2568c2ecf20Sopenharmony_ci /* button released */ 2578c2ecf20Sopenharmony_ci snd_soc_jack_report(rt700->hs_jack, rt700->jack_type, 2588c2ecf20Sopenharmony_ci SND_JACK_HEADSET | 2598c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 2608c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 2638c2ecf20Sopenharmony_ci &rt700->jack_btn_check_work, msecs_to_jiffies(200)); 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ciio_error: 2698c2ecf20Sopenharmony_ci pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic void rt700_jack_init(struct rt700_priv *rt700) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 2758c2ecf20Sopenharmony_ci snd_soc_component_get_dapm(rt700->component); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* power on */ 2788c2ecf20Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 2798c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 2808c2ecf20Sopenharmony_ci RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (rt700->hs_jack) { 2838c2ecf20Sopenharmony_ci /* Enable Jack Detection */ 2848c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 2858c2ecf20Sopenharmony_ci RT700_SET_MIC2_UNSOLICITED_ENABLE, 0x82); 2868c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 2878c2ecf20Sopenharmony_ci RT700_SET_HP_UNSOLICITED_ENABLE, 0x81); 2888c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 2898c2ecf20Sopenharmony_ci RT700_SET_INLINE_UNSOLICITED_ENABLE, 0x83); 2908c2ecf20Sopenharmony_ci rt700_index_write(rt700->regmap, 0x10, 0x2420); 2918c2ecf20Sopenharmony_ci rt700_index_write(rt700->regmap, 0x19, 0x2e11); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci dev_dbg(&rt700->slave->dev, "in %s enable\n", __func__); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 2968c2ecf20Sopenharmony_ci &rt700->jack_detect_work, msecs_to_jiffies(250)); 2978c2ecf20Sopenharmony_ci } else { 2988c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 2998c2ecf20Sopenharmony_ci RT700_SET_MIC2_UNSOLICITED_ENABLE, 0x00); 3008c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 3018c2ecf20Sopenharmony_ci RT700_SET_HP_UNSOLICITED_ENABLE, 0x00); 3028c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 3038c2ecf20Sopenharmony_ci RT700_SET_INLINE_UNSOLICITED_ENABLE, 0x00); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci dev_dbg(&rt700->slave->dev, "in %s disable\n", __func__); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* power off */ 3098c2ecf20Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 3108c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 3118c2ecf20Sopenharmony_ci RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int rt700_set_jack_detect(struct snd_soc_component *component, 3158c2ecf20Sopenharmony_ci struct snd_soc_jack *hs_jack, void *data) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci rt700->hs_jack = hs_jack; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (!rt700->hw_init) { 3228c2ecf20Sopenharmony_ci dev_dbg(&rt700->slave->dev, 3238c2ecf20Sopenharmony_ci "%s hw_init not ready yet\n", __func__); 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci rt700_jack_init(rt700); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic void rt700_get_gain(struct rt700_priv *rt700, unsigned int addr_h, 3338c2ecf20Sopenharmony_ci unsigned int addr_l, unsigned int val_h, 3348c2ecf20Sopenharmony_ci unsigned int *r_val, unsigned int *l_val) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci /* R Channel */ 3378c2ecf20Sopenharmony_ci *r_val = (val_h << 8); 3388c2ecf20Sopenharmony_ci regmap_read(rt700->regmap, addr_l, r_val); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* L Channel */ 3418c2ecf20Sopenharmony_ci val_h |= 0x20; 3428c2ecf20Sopenharmony_ci *l_val = (val_h << 8); 3438c2ecf20Sopenharmony_ci regmap_read(rt700->regmap, addr_h, l_val); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/* For Verb-Set Amplifier Gain (Verb ID = 3h) */ 3478c2ecf20Sopenharmony_cistatic int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol, 3488c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 3518c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 3528c2ecf20Sopenharmony_ci snd_soc_component_get_dapm(component); 3538c2ecf20Sopenharmony_ci struct soc_mixer_control *mc = 3548c2ecf20Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 3558c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 3568c2ecf20Sopenharmony_ci unsigned int addr_h, addr_l, val_h, val_ll, val_lr; 3578c2ecf20Sopenharmony_ci unsigned int read_ll, read_rl; 3588c2ecf20Sopenharmony_ci int i; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Can't use update bit function, so read the original value first */ 3618c2ecf20Sopenharmony_ci addr_h = mc->reg; 3628c2ecf20Sopenharmony_ci addr_l = mc->rreg; 3638c2ecf20Sopenharmony_ci if (mc->shift == RT700_DIR_OUT_SFT) /* output */ 3648c2ecf20Sopenharmony_ci val_h = 0x80; 3658c2ecf20Sopenharmony_ci else /* input */ 3668c2ecf20Sopenharmony_ci val_h = 0x0; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci rt700_get_gain(rt700, addr_h, addr_l, val_h, &read_rl, &read_ll); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* L Channel */ 3718c2ecf20Sopenharmony_ci if (mc->invert) { 3728c2ecf20Sopenharmony_ci /* for mute */ 3738c2ecf20Sopenharmony_ci val_ll = (mc->max - ucontrol->value.integer.value[0]) << 7; 3748c2ecf20Sopenharmony_ci /* keep gain */ 3758c2ecf20Sopenharmony_ci read_ll = read_ll & 0x7f; 3768c2ecf20Sopenharmony_ci val_ll |= read_ll; 3778c2ecf20Sopenharmony_ci } else { 3788c2ecf20Sopenharmony_ci /* for gain */ 3798c2ecf20Sopenharmony_ci val_ll = ((ucontrol->value.integer.value[0]) & 0x7f); 3808c2ecf20Sopenharmony_ci if (val_ll > mc->max) 3818c2ecf20Sopenharmony_ci val_ll = mc->max; 3828c2ecf20Sopenharmony_ci /* keep mute status */ 3838c2ecf20Sopenharmony_ci read_ll = read_ll & 0x80; 3848c2ecf20Sopenharmony_ci val_ll |= read_ll; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 3888c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 3898c2ecf20Sopenharmony_ci RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* R Channel */ 3928c2ecf20Sopenharmony_ci if (mc->invert) { 3938c2ecf20Sopenharmony_ci /* for mute */ 3948c2ecf20Sopenharmony_ci val_lr = (mc->max - ucontrol->value.integer.value[1]) << 7; 3958c2ecf20Sopenharmony_ci /* keep gain */ 3968c2ecf20Sopenharmony_ci read_rl = read_rl & 0x7f; 3978c2ecf20Sopenharmony_ci val_lr |= read_rl; 3988c2ecf20Sopenharmony_ci } else { 3998c2ecf20Sopenharmony_ci /* for gain */ 4008c2ecf20Sopenharmony_ci val_lr = ((ucontrol->value.integer.value[1]) & 0x7f); 4018c2ecf20Sopenharmony_ci if (val_lr > mc->max) 4028c2ecf20Sopenharmony_ci val_lr = mc->max; 4038c2ecf20Sopenharmony_ci /* keep mute status */ 4048c2ecf20Sopenharmony_ci read_rl = read_rl & 0x80; 4058c2ecf20Sopenharmony_ci val_lr |= read_rl; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { /* retry 3 times at most */ 4098c2ecf20Sopenharmony_ci if (val_ll == val_lr) { 4108c2ecf20Sopenharmony_ci /* Set both L/R channels at the same time */ 4118c2ecf20Sopenharmony_ci val_h = (1 << mc->shift) | (3 << 4); 4128c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 4138c2ecf20Sopenharmony_ci addr_h, (val_h << 8 | val_ll)); 4148c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 4158c2ecf20Sopenharmony_ci addr_l, (val_h << 8 | val_ll)); 4168c2ecf20Sopenharmony_ci } else { 4178c2ecf20Sopenharmony_ci /* Lch*/ 4188c2ecf20Sopenharmony_ci val_h = (1 << mc->shift) | (1 << 5); 4198c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 4208c2ecf20Sopenharmony_ci addr_h, (val_h << 8 | val_ll)); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Rch */ 4238c2ecf20Sopenharmony_ci val_h = (1 << mc->shift) | (1 << 4); 4248c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 4258c2ecf20Sopenharmony_ci addr_l, (val_h << 8 | val_lr)); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci /* check result */ 4288c2ecf20Sopenharmony_ci if (mc->shift == RT700_DIR_OUT_SFT) /* output */ 4298c2ecf20Sopenharmony_ci val_h = 0x80; 4308c2ecf20Sopenharmony_ci else /* input */ 4318c2ecf20Sopenharmony_ci val_h = 0x0; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci rt700_get_gain(rt700, addr_h, addr_l, val_h, 4348c2ecf20Sopenharmony_ci &read_rl, &read_ll); 4358c2ecf20Sopenharmony_ci if (read_rl == val_lr && read_ll == val_ll) 4368c2ecf20Sopenharmony_ci break; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 4408c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 4418c2ecf20Sopenharmony_ci RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int rt700_set_amp_gain_get(struct snd_kcontrol *kcontrol, 4468c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 4498c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 4508c2ecf20Sopenharmony_ci struct soc_mixer_control *mc = 4518c2ecf20Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 4528c2ecf20Sopenharmony_ci unsigned int addr_h, addr_l, val_h; 4538c2ecf20Sopenharmony_ci unsigned int read_ll, read_rl; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci addr_h = mc->reg; 4568c2ecf20Sopenharmony_ci addr_l = mc->rreg; 4578c2ecf20Sopenharmony_ci if (mc->shift == RT700_DIR_OUT_SFT) /* output */ 4588c2ecf20Sopenharmony_ci val_h = 0x80; 4598c2ecf20Sopenharmony_ci else /* input */ 4608c2ecf20Sopenharmony_ci val_h = 0x0; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci rt700_get_gain(rt700, addr_h, addr_l, val_h, &read_rl, &read_ll); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (mc->invert) { 4658c2ecf20Sopenharmony_ci /* for mute status */ 4668c2ecf20Sopenharmony_ci read_ll = !((read_ll & 0x80) >> RT700_MUTE_SFT); 4678c2ecf20Sopenharmony_ci read_rl = !((read_rl & 0x80) >> RT700_MUTE_SFT); 4688c2ecf20Sopenharmony_ci } else { 4698c2ecf20Sopenharmony_ci /* for gain */ 4708c2ecf20Sopenharmony_ci read_ll = read_ll & 0x7f; 4718c2ecf20Sopenharmony_ci read_rl = read_rl & 0x7f; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = read_ll; 4748c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = read_rl; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); 4808c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); 4818c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new rt700_snd_controls[] = { 4848c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("DAC Front Playback Volume", 4858c2ecf20Sopenharmony_ci RT700_SET_GAIN_DAC1_H, RT700_SET_GAIN_DAC1_L, 4868c2ecf20Sopenharmony_ci RT700_DIR_OUT_SFT, 0x57, 0, 4878c2ecf20Sopenharmony_ci rt700_set_amp_gain_get, rt700_set_amp_gain_put, out_vol_tlv), 4888c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", 4898c2ecf20Sopenharmony_ci RT700_SET_GAIN_ADC2_H, RT700_SET_GAIN_ADC2_L, 4908c2ecf20Sopenharmony_ci RT700_DIR_IN_SFT, 1, 1, 4918c2ecf20Sopenharmony_ci rt700_set_amp_gain_get, rt700_set_amp_gain_put), 4928c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", 4938c2ecf20Sopenharmony_ci RT700_SET_GAIN_ADC1_H, RT700_SET_GAIN_ADC1_L, 4948c2ecf20Sopenharmony_ci RT700_DIR_IN_SFT, 1, 1, 4958c2ecf20Sopenharmony_ci rt700_set_amp_gain_get, rt700_set_amp_gain_put), 4968c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", 4978c2ecf20Sopenharmony_ci RT700_SET_GAIN_ADC2_H, RT700_SET_GAIN_ADC2_L, 4988c2ecf20Sopenharmony_ci RT700_DIR_IN_SFT, 0x3f, 0, 4998c2ecf20Sopenharmony_ci rt700_set_amp_gain_get, rt700_set_amp_gain_put, in_vol_tlv), 5008c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", 5018c2ecf20Sopenharmony_ci RT700_SET_GAIN_ADC1_H, RT700_SET_GAIN_ADC1_L, 5028c2ecf20Sopenharmony_ci RT700_DIR_IN_SFT, 0x3f, 0, 5038c2ecf20Sopenharmony_ci rt700_set_amp_gain_get, rt700_set_amp_gain_put, in_vol_tlv), 5048c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("AMIC Volume", 5058c2ecf20Sopenharmony_ci RT700_SET_GAIN_AMIC_H, RT700_SET_GAIN_AMIC_L, 5068c2ecf20Sopenharmony_ci RT700_DIR_IN_SFT, 3, 0, 5078c2ecf20Sopenharmony_ci rt700_set_amp_gain_get, rt700_set_amp_gain_put, mic_vol_tlv), 5088c2ecf20Sopenharmony_ci}; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int rt700_mux_get(struct snd_kcontrol *kcontrol, 5118c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct snd_soc_component *component = 5148c2ecf20Sopenharmony_ci snd_soc_dapm_kcontrol_component(kcontrol); 5158c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 5168c2ecf20Sopenharmony_ci unsigned int reg, val = 0, nid; 5178c2ecf20Sopenharmony_ci int ret; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (strstr(ucontrol->id.name, "HPO Mux")) 5208c2ecf20Sopenharmony_ci nid = RT700_HP_OUT; 5218c2ecf20Sopenharmony_ci else if (strstr(ucontrol->id.name, "ADC 22 Mux")) 5228c2ecf20Sopenharmony_ci nid = RT700_MIXER_IN1; 5238c2ecf20Sopenharmony_ci else if (strstr(ucontrol->id.name, "ADC 23 Mux")) 5248c2ecf20Sopenharmony_ci nid = RT700_MIXER_IN2; 5258c2ecf20Sopenharmony_ci else 5268c2ecf20Sopenharmony_ci return -EINVAL; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* vid = 0xf01 */ 5298c2ecf20Sopenharmony_ci reg = RT700_VERB_SET_CONNECT_SEL | nid; 5308c2ecf20Sopenharmony_ci ret = regmap_read(rt700->regmap, reg, &val); 5318c2ecf20Sopenharmony_ci if (ret < 0) 5328c2ecf20Sopenharmony_ci return ret; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = val; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic int rt700_mux_put(struct snd_kcontrol *kcontrol, 5408c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct snd_soc_component *component = 5438c2ecf20Sopenharmony_ci snd_soc_dapm_kcontrol_component(kcontrol); 5448c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 5458c2ecf20Sopenharmony_ci snd_soc_dapm_kcontrol_dapm(kcontrol); 5468c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 5478c2ecf20Sopenharmony_ci struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 5488c2ecf20Sopenharmony_ci unsigned int *item = ucontrol->value.enumerated.item; 5498c2ecf20Sopenharmony_ci unsigned int val, val2 = 0, change, reg, nid; 5508c2ecf20Sopenharmony_ci int ret; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (item[0] >= e->items) 5538c2ecf20Sopenharmony_ci return -EINVAL; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (strstr(ucontrol->id.name, "HPO Mux")) 5568c2ecf20Sopenharmony_ci nid = RT700_HP_OUT; 5578c2ecf20Sopenharmony_ci else if (strstr(ucontrol->id.name, "ADC 22 Mux")) 5588c2ecf20Sopenharmony_ci nid = RT700_MIXER_IN1; 5598c2ecf20Sopenharmony_ci else if (strstr(ucontrol->id.name, "ADC 23 Mux")) 5608c2ecf20Sopenharmony_ci nid = RT700_MIXER_IN2; 5618c2ecf20Sopenharmony_ci else 5628c2ecf20Sopenharmony_ci return -EINVAL; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* Verb ID = 0x701h */ 5658c2ecf20Sopenharmony_ci val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci reg = RT700_VERB_SET_CONNECT_SEL | nid; 5688c2ecf20Sopenharmony_ci ret = regmap_read(rt700->regmap, reg, &val2); 5698c2ecf20Sopenharmony_ci if (ret < 0) 5708c2ecf20Sopenharmony_ci return ret; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (val == val2) 5738c2ecf20Sopenharmony_ci change = 0; 5748c2ecf20Sopenharmony_ci else 5758c2ecf20Sopenharmony_ci change = 1; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (change) { 5788c2ecf20Sopenharmony_ci reg = RT700_VERB_SET_CONNECT_SEL | nid; 5798c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, reg, val); 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci snd_soc_dapm_mux_update_power(dapm, kcontrol, 5838c2ecf20Sopenharmony_ci item[0], e, NULL); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci return change; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic const char * const adc_mux_text[] = { 5898c2ecf20Sopenharmony_ci "MIC2", 5908c2ecf20Sopenharmony_ci "LINE1", 5918c2ecf20Sopenharmony_ci "LINE2", 5928c2ecf20Sopenharmony_ci "DMIC", 5938c2ecf20Sopenharmony_ci}; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 5968c2ecf20Sopenharmony_ci rt700_adc22_enum, SND_SOC_NOPM, 0, adc_mux_text); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 5998c2ecf20Sopenharmony_ci rt700_adc23_enum, SND_SOC_NOPM, 0, adc_mux_text); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new rt700_adc22_mux = 6028c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt700_adc22_enum, 6038c2ecf20Sopenharmony_ci rt700_mux_get, rt700_mux_put); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new rt700_adc23_mux = 6068c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt700_adc23_enum, 6078c2ecf20Sopenharmony_ci rt700_mux_get, rt700_mux_put); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic const char * const out_mux_text[] = { 6108c2ecf20Sopenharmony_ci "Front", 6118c2ecf20Sopenharmony_ci "Surround", 6128c2ecf20Sopenharmony_ci}; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 6158c2ecf20Sopenharmony_ci rt700_hp_enum, SND_SOC_NOPM, 0, out_mux_text); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new rt700_hp_mux = 6188c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("HP Mux", rt700_hp_enum, 6198c2ecf20Sopenharmony_ci rt700_mux_get, rt700_mux_put); 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int rt700_dac_front_event(struct snd_soc_dapm_widget *w, 6228c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct snd_soc_component *component = 6258c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 6268c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci switch (event) { 6298c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 6308c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 6318c2ecf20Sopenharmony_ci RT700_SET_STREAMID_DAC1, 0x10); 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 6348c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 6358c2ecf20Sopenharmony_ci RT700_SET_STREAMID_DAC1, 0x00); 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci return 0; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int rt700_dac_surround_event(struct snd_soc_dapm_widget *w, 6428c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct snd_soc_component *component = 6458c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 6468c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci switch (event) { 6498c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 6508c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 6518c2ecf20Sopenharmony_ci RT700_SET_STREAMID_DAC2, 0x10); 6528c2ecf20Sopenharmony_ci break; 6538c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 6548c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 6558c2ecf20Sopenharmony_ci RT700_SET_STREAMID_DAC2, 0x00); 6568c2ecf20Sopenharmony_ci break; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci return 0; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic int rt700_adc_09_event(struct snd_soc_dapm_widget *w, 6628c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct snd_soc_component *component = 6658c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 6668c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci switch (event) { 6698c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 6708c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 6718c2ecf20Sopenharmony_ci RT700_SET_STREAMID_ADC1, 0x10); 6728c2ecf20Sopenharmony_ci break; 6738c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 6748c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 6758c2ecf20Sopenharmony_ci RT700_SET_STREAMID_ADC1, 0x00); 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci return 0; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic int rt700_adc_08_event(struct snd_soc_dapm_widget *w, 6828c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci struct snd_soc_component *component = 6858c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 6868c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci switch (event) { 6898c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 6908c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 6918c2ecf20Sopenharmony_ci RT700_SET_STREAMID_ADC2, 0x10); 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 6948c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 6958c2ecf20Sopenharmony_ci RT700_SET_STREAMID_ADC2, 0x00); 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci return 0; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic int rt700_hpo_mux_event(struct snd_soc_dapm_widget *w, 7028c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct snd_soc_component *component = 7058c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 7068c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 7078c2ecf20Sopenharmony_ci unsigned int val_h = (1 << RT700_DIR_OUT_SFT) | (0x3 << 4); 7088c2ecf20Sopenharmony_ci unsigned int val_l; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci switch (event) { 7118c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 7128c2ecf20Sopenharmony_ci val_l = 0x00; 7138c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 7148c2ecf20Sopenharmony_ci RT700_SET_GAIN_HP_H, (val_h << 8 | val_l)); 7158c2ecf20Sopenharmony_ci break; 7168c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 7178c2ecf20Sopenharmony_ci val_l = (1 << RT700_MUTE_SFT); 7188c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 7198c2ecf20Sopenharmony_ci RT700_SET_GAIN_HP_H, (val_h << 8 | val_l)); 7208c2ecf20Sopenharmony_ci usleep_range(50000, 55000); 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci return 0; 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic int rt700_spk_pga_event(struct snd_soc_dapm_widget *w, 7278c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct snd_soc_component *component = 7308c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 7318c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 7328c2ecf20Sopenharmony_ci unsigned int val_h = (1 << RT700_DIR_OUT_SFT) | (0x3 << 4); 7338c2ecf20Sopenharmony_ci unsigned int val_l; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci switch (event) { 7368c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 7378c2ecf20Sopenharmony_ci val_l = 0x00; 7388c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 7398c2ecf20Sopenharmony_ci RT700_SET_GAIN_SPK_H, (val_h << 8 | val_l)); 7408c2ecf20Sopenharmony_ci break; 7418c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 7428c2ecf20Sopenharmony_ci val_l = (1 << RT700_MUTE_SFT); 7438c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 7448c2ecf20Sopenharmony_ci RT700_SET_GAIN_SPK_H, (val_h << 8 | val_l)); 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci return 0; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget rt700_dapm_widgets[] = { 7518c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HP"), 7528c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("SPK"), 7538c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("DMIC1"), 7548c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("DMIC2"), 7558c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC2"), 7568c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("LINE1"), 7578c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("LINE2"), 7588c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC Front", NULL, SND_SOC_NOPM, 0, 0, 7598c2ecf20Sopenharmony_ci rt700_dac_front_event, 7608c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 7618c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC Surround", NULL, SND_SOC_NOPM, 0, 0, 7628c2ecf20Sopenharmony_ci rt700_dac_surround_event, 7638c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 7648c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX_E("HPO Mux", SND_SOC_NOPM, 0, 0, &rt700_hp_mux, 7658c2ecf20Sopenharmony_ci rt700_hpo_mux_event, 7668c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 7678c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA_E("SPK PGA", SND_SOC_NOPM, 0, 0, NULL, 0, 7688c2ecf20Sopenharmony_ci rt700_spk_pga_event, 7698c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 7708c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC_E("ADC 09", NULL, SND_SOC_NOPM, 0, 0, 7718c2ecf20Sopenharmony_ci rt700_adc_09_event, 7728c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 7738c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC_E("ADC 08", NULL, SND_SOC_NOPM, 0, 0, 7748c2ecf20Sopenharmony_ci rt700_adc_08_event, 7758c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 7768c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, 7778c2ecf20Sopenharmony_ci &rt700_adc22_mux), 7788c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, 7798c2ecf20Sopenharmony_ci &rt700_adc23_mux), 7808c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0), 7818c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), 7828c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0), 7838c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), 7848c2ecf20Sopenharmony_ci}; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route rt700_audio_map[] = { 7878c2ecf20Sopenharmony_ci {"DAC Front", NULL, "DP1RX"}, 7888c2ecf20Sopenharmony_ci {"DAC Surround", NULL, "DP3RX"}, 7898c2ecf20Sopenharmony_ci {"DP2TX", NULL, "ADC 09"}, 7908c2ecf20Sopenharmony_ci {"DP4TX", NULL, "ADC 08"}, 7918c2ecf20Sopenharmony_ci {"ADC 09", NULL, "ADC 22 Mux"}, 7928c2ecf20Sopenharmony_ci {"ADC 08", NULL, "ADC 23 Mux"}, 7938c2ecf20Sopenharmony_ci {"ADC 22 Mux", "DMIC", "DMIC1"}, 7948c2ecf20Sopenharmony_ci {"ADC 22 Mux", "LINE1", "LINE1"}, 7958c2ecf20Sopenharmony_ci {"ADC 22 Mux", "LINE2", "LINE2"}, 7968c2ecf20Sopenharmony_ci {"ADC 22 Mux", "MIC2", "MIC2"}, 7978c2ecf20Sopenharmony_ci {"ADC 23 Mux", "DMIC", "DMIC2"}, 7988c2ecf20Sopenharmony_ci {"ADC 23 Mux", "LINE1", "LINE1"}, 7998c2ecf20Sopenharmony_ci {"ADC 23 Mux", "LINE2", "LINE2"}, 8008c2ecf20Sopenharmony_ci {"ADC 23 Mux", "MIC2", "MIC2"}, 8018c2ecf20Sopenharmony_ci {"HPO Mux", "Front", "DAC Front"}, 8028c2ecf20Sopenharmony_ci {"HPO Mux", "Surround", "DAC Surround"}, 8038c2ecf20Sopenharmony_ci {"HP", NULL, "HPO Mux"}, 8048c2ecf20Sopenharmony_ci {"SPK PGA", NULL, "DAC Front"}, 8058c2ecf20Sopenharmony_ci {"SPK", NULL, "SPK PGA"}, 8068c2ecf20Sopenharmony_ci}; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic int rt700_probe(struct snd_soc_component *component) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci rt700->component = component; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return 0; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic int rt700_set_bias_level(struct snd_soc_component *component, 8188c2ecf20Sopenharmony_ci enum snd_soc_bias_level level) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 8218c2ecf20Sopenharmony_ci snd_soc_component_get_dapm(component); 8228c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci switch (level) { 8258c2ecf20Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 8268c2ecf20Sopenharmony_ci if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { 8278c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 8288c2ecf20Sopenharmony_ci RT700_SET_AUDIO_POWER_STATE, 8298c2ecf20Sopenharmony_ci AC_PWRST_D0); 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci break; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 8348c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 8358c2ecf20Sopenharmony_ci RT700_SET_AUDIO_POWER_STATE, 8368c2ecf20Sopenharmony_ci AC_PWRST_D3); 8378c2ecf20Sopenharmony_ci break; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci default: 8408c2ecf20Sopenharmony_ci break; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci dapm->bias_level = level; 8438c2ecf20Sopenharmony_ci return 0; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_codec_dev_rt700 = { 8478c2ecf20Sopenharmony_ci .probe = rt700_probe, 8488c2ecf20Sopenharmony_ci .set_bias_level = rt700_set_bias_level, 8498c2ecf20Sopenharmony_ci .controls = rt700_snd_controls, 8508c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(rt700_snd_controls), 8518c2ecf20Sopenharmony_ci .dapm_widgets = rt700_dapm_widgets, 8528c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(rt700_dapm_widgets), 8538c2ecf20Sopenharmony_ci .dapm_routes = rt700_audio_map, 8548c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(rt700_audio_map), 8558c2ecf20Sopenharmony_ci .set_jack = rt700_set_jack_detect, 8568c2ecf20Sopenharmony_ci}; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic int rt700_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, 8598c2ecf20Sopenharmony_ci int direction) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci struct sdw_stream_data *stream; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (!sdw_stream) 8648c2ecf20Sopenharmony_ci return 0; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci stream = kzalloc(sizeof(*stream), GFP_KERNEL); 8678c2ecf20Sopenharmony_ci if (!stream) 8688c2ecf20Sopenharmony_ci return -ENOMEM; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ 8738c2ecf20Sopenharmony_ci if (direction == SNDRV_PCM_STREAM_PLAYBACK) 8748c2ecf20Sopenharmony_ci dai->playback_dma_data = stream; 8758c2ecf20Sopenharmony_ci else 8768c2ecf20Sopenharmony_ci dai->capture_dma_data = stream; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci return 0; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic void rt700_shutdown(struct snd_pcm_substream *substream, 8828c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct sdw_stream_data *stream; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci stream = snd_soc_dai_get_dma_data(dai, substream); 8878c2ecf20Sopenharmony_ci snd_soc_dai_set_dma_data(dai, substream, NULL); 8888c2ecf20Sopenharmony_ci kfree(stream); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic int rt700_pcm_hw_params(struct snd_pcm_substream *substream, 8928c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 8938c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 8968c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 8978c2ecf20Sopenharmony_ci struct sdw_stream_config stream_config; 8988c2ecf20Sopenharmony_ci struct sdw_port_config port_config; 8998c2ecf20Sopenharmony_ci enum sdw_data_direction direction; 9008c2ecf20Sopenharmony_ci struct sdw_stream_data *stream; 9018c2ecf20Sopenharmony_ci int retval, port, num_channels; 9028c2ecf20Sopenharmony_ci unsigned int val = 0; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "%s %s", __func__, dai->name); 9058c2ecf20Sopenharmony_ci stream = snd_soc_dai_get_dma_data(dai, substream); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (!stream) 9088c2ecf20Sopenharmony_ci return -EINVAL; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (!rt700->slave) 9118c2ecf20Sopenharmony_ci return -EINVAL; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* SoundWire specific configuration */ 9148c2ecf20Sopenharmony_ci /* This code assumes port 1 for playback and port 2 for capture */ 9158c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 9168c2ecf20Sopenharmony_ci direction = SDW_DATA_DIR_RX; 9178c2ecf20Sopenharmony_ci port = 1; 9188c2ecf20Sopenharmony_ci } else { 9198c2ecf20Sopenharmony_ci direction = SDW_DATA_DIR_TX; 9208c2ecf20Sopenharmony_ci port = 2; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci switch (dai->id) { 9248c2ecf20Sopenharmony_ci case RT700_AIF1: 9258c2ecf20Sopenharmony_ci break; 9268c2ecf20Sopenharmony_ci case RT700_AIF2: 9278c2ecf20Sopenharmony_ci port += 2; 9288c2ecf20Sopenharmony_ci break; 9298c2ecf20Sopenharmony_ci default: 9308c2ecf20Sopenharmony_ci dev_err(component->dev, "Invalid DAI id %d\n", dai->id); 9318c2ecf20Sopenharmony_ci return -EINVAL; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci stream_config.frame_rate = params_rate(params); 9358c2ecf20Sopenharmony_ci stream_config.ch_count = params_channels(params); 9368c2ecf20Sopenharmony_ci stream_config.bps = snd_pcm_format_width(params_format(params)); 9378c2ecf20Sopenharmony_ci stream_config.direction = direction; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci num_channels = params_channels(params); 9408c2ecf20Sopenharmony_ci port_config.ch_mask = (1 << (num_channels)) - 1; 9418c2ecf20Sopenharmony_ci port_config.num = port; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci retval = sdw_stream_add_slave(rt700->slave, &stream_config, 9448c2ecf20Sopenharmony_ci &port_config, 1, stream->sdw_stream); 9458c2ecf20Sopenharmony_ci if (retval) { 9468c2ecf20Sopenharmony_ci dev_err(dai->dev, "Unable to configure port\n"); 9478c2ecf20Sopenharmony_ci return retval; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (params_channels(params) <= 16) { 9518c2ecf20Sopenharmony_ci /* bit 3:0 Number of Channel */ 9528c2ecf20Sopenharmony_ci val |= (params_channels(params) - 1); 9538c2ecf20Sopenharmony_ci } else { 9548c2ecf20Sopenharmony_ci dev_err(component->dev, "Unsupported channels %d\n", 9558c2ecf20Sopenharmony_ci params_channels(params)); 9568c2ecf20Sopenharmony_ci return -EINVAL; 9578c2ecf20Sopenharmony_ci } 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci switch (params_width(params)) { 9608c2ecf20Sopenharmony_ci /* bit 6:4 Bits per Sample */ 9618c2ecf20Sopenharmony_ci case 8: 9628c2ecf20Sopenharmony_ci break; 9638c2ecf20Sopenharmony_ci case 16: 9648c2ecf20Sopenharmony_ci val |= (0x1 << 4); 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci case 20: 9678c2ecf20Sopenharmony_ci val |= (0x2 << 4); 9688c2ecf20Sopenharmony_ci break; 9698c2ecf20Sopenharmony_ci case 24: 9708c2ecf20Sopenharmony_ci val |= (0x3 << 4); 9718c2ecf20Sopenharmony_ci break; 9728c2ecf20Sopenharmony_ci case 32: 9738c2ecf20Sopenharmony_ci val |= (0x4 << 4); 9748c2ecf20Sopenharmony_ci break; 9758c2ecf20Sopenharmony_ci default: 9768c2ecf20Sopenharmony_ci return -EINVAL; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* 48Khz */ 9808c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_DAC_FORMAT_H, val); 9818c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_ADC_FORMAT_H, val); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci return retval; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic int rt700_pcm_hw_free(struct snd_pcm_substream *substream, 9878c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 9908c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component); 9918c2ecf20Sopenharmony_ci struct sdw_stream_data *stream = 9928c2ecf20Sopenharmony_ci snd_soc_dai_get_dma_data(dai, substream); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (!rt700->slave) 9958c2ecf20Sopenharmony_ci return -EINVAL; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci sdw_stream_remove_slave(rt700->slave, stream->sdw_stream); 9988c2ecf20Sopenharmony_ci return 0; 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci#define RT700_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) 10028c2ecf20Sopenharmony_ci#define RT700_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ 10038c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic struct snd_soc_dai_ops rt700_ops = { 10068c2ecf20Sopenharmony_ci .hw_params = rt700_pcm_hw_params, 10078c2ecf20Sopenharmony_ci .hw_free = rt700_pcm_hw_free, 10088c2ecf20Sopenharmony_ci .set_stream = rt700_set_sdw_stream, 10098c2ecf20Sopenharmony_ci .shutdown = rt700_shutdown, 10108c2ecf20Sopenharmony_ci}; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver rt700_dai[] = { 10138c2ecf20Sopenharmony_ci { 10148c2ecf20Sopenharmony_ci .name = "rt700-aif1", 10158c2ecf20Sopenharmony_ci .id = RT700_AIF1, 10168c2ecf20Sopenharmony_ci .playback = { 10178c2ecf20Sopenharmony_ci .stream_name = "DP1 Playback", 10188c2ecf20Sopenharmony_ci .channels_min = 1, 10198c2ecf20Sopenharmony_ci .channels_max = 2, 10208c2ecf20Sopenharmony_ci .rates = RT700_STEREO_RATES, 10218c2ecf20Sopenharmony_ci .formats = RT700_FORMATS, 10228c2ecf20Sopenharmony_ci }, 10238c2ecf20Sopenharmony_ci .capture = { 10248c2ecf20Sopenharmony_ci .stream_name = "DP2 Capture", 10258c2ecf20Sopenharmony_ci .channels_min = 1, 10268c2ecf20Sopenharmony_ci .channels_max = 2, 10278c2ecf20Sopenharmony_ci .rates = RT700_STEREO_RATES, 10288c2ecf20Sopenharmony_ci .formats = RT700_FORMATS, 10298c2ecf20Sopenharmony_ci }, 10308c2ecf20Sopenharmony_ci .ops = &rt700_ops, 10318c2ecf20Sopenharmony_ci }, 10328c2ecf20Sopenharmony_ci { 10338c2ecf20Sopenharmony_ci .name = "rt700-aif2", 10348c2ecf20Sopenharmony_ci .id = RT700_AIF2, 10358c2ecf20Sopenharmony_ci .playback = { 10368c2ecf20Sopenharmony_ci .stream_name = "DP3 Playback", 10378c2ecf20Sopenharmony_ci .channels_min = 1, 10388c2ecf20Sopenharmony_ci .channels_max = 2, 10398c2ecf20Sopenharmony_ci .rates = RT700_STEREO_RATES, 10408c2ecf20Sopenharmony_ci .formats = RT700_FORMATS, 10418c2ecf20Sopenharmony_ci }, 10428c2ecf20Sopenharmony_ci .capture = { 10438c2ecf20Sopenharmony_ci .stream_name = "DP4 Capture", 10448c2ecf20Sopenharmony_ci .channels_min = 1, 10458c2ecf20Sopenharmony_ci .channels_max = 2, 10468c2ecf20Sopenharmony_ci .rates = RT700_STEREO_RATES, 10478c2ecf20Sopenharmony_ci .formats = RT700_FORMATS, 10488c2ecf20Sopenharmony_ci }, 10498c2ecf20Sopenharmony_ci .ops = &rt700_ops, 10508c2ecf20Sopenharmony_ci }, 10518c2ecf20Sopenharmony_ci}; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci/* Bus clock frequency */ 10548c2ecf20Sopenharmony_ci#define RT700_CLK_FREQ_9600000HZ 9600000 10558c2ecf20Sopenharmony_ci#define RT700_CLK_FREQ_12000000HZ 12000000 10568c2ecf20Sopenharmony_ci#define RT700_CLK_FREQ_6000000HZ 6000000 10578c2ecf20Sopenharmony_ci#define RT700_CLK_FREQ_4800000HZ 4800000 10588c2ecf20Sopenharmony_ci#define RT700_CLK_FREQ_2400000HZ 2400000 10598c2ecf20Sopenharmony_ci#define RT700_CLK_FREQ_12288000HZ 12288000 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ciint rt700_clock_config(struct device *dev) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = dev_get_drvdata(dev); 10648c2ecf20Sopenharmony_ci unsigned int clk_freq, value; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci clk_freq = (rt700->params.curr_dr_freq >> 1); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci switch (clk_freq) { 10698c2ecf20Sopenharmony_ci case RT700_CLK_FREQ_12000000HZ: 10708c2ecf20Sopenharmony_ci value = 0x0; 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci case RT700_CLK_FREQ_6000000HZ: 10738c2ecf20Sopenharmony_ci value = 0x1; 10748c2ecf20Sopenharmony_ci break; 10758c2ecf20Sopenharmony_ci case RT700_CLK_FREQ_9600000HZ: 10768c2ecf20Sopenharmony_ci value = 0x2; 10778c2ecf20Sopenharmony_ci break; 10788c2ecf20Sopenharmony_ci case RT700_CLK_FREQ_4800000HZ: 10798c2ecf20Sopenharmony_ci value = 0x3; 10808c2ecf20Sopenharmony_ci break; 10818c2ecf20Sopenharmony_ci case RT700_CLK_FREQ_2400000HZ: 10828c2ecf20Sopenharmony_ci value = 0x4; 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci case RT700_CLK_FREQ_12288000HZ: 10858c2ecf20Sopenharmony_ci value = 0x5; 10868c2ecf20Sopenharmony_ci break; 10878c2ecf20Sopenharmony_ci default: 10888c2ecf20Sopenharmony_ci return -EINVAL; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0xe0, value); 10928c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0xf0, value); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci return 0; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ciint rt700_init(struct device *dev, struct regmap *sdw_regmap, 11008c2ecf20Sopenharmony_ci struct regmap *regmap, struct sdw_slave *slave) 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci struct rt700_priv *rt700; 11048c2ecf20Sopenharmony_ci int ret; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci rt700 = devm_kzalloc(dev, sizeof(*rt700), GFP_KERNEL); 11078c2ecf20Sopenharmony_ci if (!rt700) 11088c2ecf20Sopenharmony_ci return -ENOMEM; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci dev_set_drvdata(dev, rt700); 11118c2ecf20Sopenharmony_ci rt700->slave = slave; 11128c2ecf20Sopenharmony_ci rt700->sdw_regmap = sdw_regmap; 11138c2ecf20Sopenharmony_ci rt700->regmap = regmap; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* 11168c2ecf20Sopenharmony_ci * Mark hw_init to false 11178c2ecf20Sopenharmony_ci * HW init will be performed when device reports present 11188c2ecf20Sopenharmony_ci */ 11198c2ecf20Sopenharmony_ci rt700->hw_init = false; 11208c2ecf20Sopenharmony_ci rt700->first_hw_init = false; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(dev, 11238c2ecf20Sopenharmony_ci &soc_codec_dev_rt700, 11248c2ecf20Sopenharmony_ci rt700_dai, 11258c2ecf20Sopenharmony_ci ARRAY_SIZE(rt700_dai)); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci dev_dbg(&slave->dev, "%s\n", __func__); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci return ret; 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ciint rt700_io_init(struct device *dev, struct sdw_slave *slave) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci struct rt700_priv *rt700 = dev_get_drvdata(dev); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci if (rt700->hw_init) 11378c2ecf20Sopenharmony_ci return 0; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci if (rt700->first_hw_init) { 11408c2ecf20Sopenharmony_ci regcache_cache_only(rt700->regmap, false); 11418c2ecf20Sopenharmony_ci regcache_cache_bypass(rt700->regmap, true); 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* 11458c2ecf20Sopenharmony_ci * PM runtime is only enabled when a Slave reports as Attached 11468c2ecf20Sopenharmony_ci */ 11478c2ecf20Sopenharmony_ci if (!rt700->first_hw_init) { 11488c2ecf20Sopenharmony_ci /* set autosuspend parameters */ 11498c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&slave->dev, 3000); 11508c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&slave->dev); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci /* update count of parent 'active' children */ 11538c2ecf20Sopenharmony_ci pm_runtime_set_active(&slave->dev); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* make sure the device does not suspend immediately */ 11568c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(&slave->dev); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci pm_runtime_enable(&slave->dev); 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&slave->dev); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci /* reset */ 11648c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0xff01, 0x0000); 11658c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x7520, 0x001a); 11668c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x7420, 0xc003); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci /* power on */ 11698c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 11708c2ecf20Sopenharmony_ci /* Set Pin Widget */ 11718c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_SET_PIN_HP, 0x40); 11728c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_SET_PIN_SPK, 0x40); 11738c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_SET_EAPD_SPK, RT700_EAPD_HIGH); 11748c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_SET_PIN_DMIC1, 0x20); 11758c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_SET_PIN_DMIC2, 0x20); 11768c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_SET_PIN_MIC2, 0x20); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* Set Configuration Default */ 11798c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4f12, 0x91); 11808c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4e12, 0xd6); 11818c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4d12, 0x11); 11828c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4c12, 0x20); 11838c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4f13, 0x91); 11848c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4e13, 0xd6); 11858c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4d13, 0x11); 11868c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4c13, 0x21); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4f19, 0x02); 11898c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4e19, 0xa1); 11908c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4d19, 0x90); 11918c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x4c19, 0x80); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci /* Enable Line2 */ 11948c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x371b, 0x40); 11958c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x731b, 0xb0); 11968c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, 0x839b, 0x00); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci /* Set index */ 11998c2ecf20Sopenharmony_ci rt700_index_write(rt700->regmap, 0x4a, 0x201b); 12008c2ecf20Sopenharmony_ci rt700_index_write(rt700->regmap, 0x45, 0x5089); 12018c2ecf20Sopenharmony_ci rt700_index_write(rt700->regmap, 0x6b, 0x5064); 12028c2ecf20Sopenharmony_ci rt700_index_write(rt700->regmap, 0x48, 0xd249); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* Finish Initial Settings, set power to D3 */ 12058c2ecf20Sopenharmony_ci regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (!rt700->first_hw_init) { 12088c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&rt700->jack_detect_work, 12098c2ecf20Sopenharmony_ci rt700_jack_detect_handler); 12108c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&rt700->jack_btn_check_work, 12118c2ecf20Sopenharmony_ci rt700_btn_check_handler); 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci /* 12158c2ecf20Sopenharmony_ci * if set_jack callback occurred early than io_init, 12168c2ecf20Sopenharmony_ci * we set up the jack detection function now 12178c2ecf20Sopenharmony_ci */ 12188c2ecf20Sopenharmony_ci if (rt700->hs_jack) 12198c2ecf20Sopenharmony_ci rt700_jack_init(rt700); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (rt700->first_hw_init) { 12228c2ecf20Sopenharmony_ci regcache_cache_bypass(rt700->regmap, false); 12238c2ecf20Sopenharmony_ci regcache_mark_dirty(rt700->regmap); 12248c2ecf20Sopenharmony_ci } else 12258c2ecf20Sopenharmony_ci rt700->first_hw_init = true; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci /* Mark Slave initialization complete */ 12288c2ecf20Sopenharmony_ci rt700->hw_init = true; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(&slave->dev); 12318c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(&slave->dev); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci return 0; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC RT700 driver SDW"); 12398c2ecf20Sopenharmony_ciMODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); 12408c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1241