18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// rt711.c -- rt711 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 "rt711.h" 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int rt711_index_write(struct regmap *regmap, 328c2ecf20Sopenharmony_ci unsigned int nid, unsigned int reg, unsigned int value) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci int ret; 358c2ecf20Sopenharmony_ci unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 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 rt711_index_read(struct regmap *regmap, 468c2ecf20Sopenharmony_ci unsigned int nid, unsigned int reg, unsigned int *value) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci int ret; 498c2ecf20Sopenharmony_ci unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 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 int rt711_index_update_bits(struct regmap *regmap, unsigned int nid, 618c2ecf20Sopenharmony_ci unsigned int reg, unsigned int mask, unsigned int val) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci unsigned int tmp, orig; 648c2ecf20Sopenharmony_ci int ret; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci ret = rt711_index_read(regmap, nid, reg, &orig); 678c2ecf20Sopenharmony_ci if (ret < 0) 688c2ecf20Sopenharmony_ci return ret; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci tmp = orig & ~mask; 718c2ecf20Sopenharmony_ci tmp |= val & mask; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return rt711_index_write(regmap, nid, reg, tmp); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic void rt711_reset(struct regmap *regmap) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci regmap_write(regmap, RT711_FUNC_RESET, 0); 798c2ecf20Sopenharmony_ci rt711_index_update_bits(regmap, RT711_VENDOR_REG, 808c2ecf20Sopenharmony_ci RT711_PARA_VERB_CTL, RT711_HIDDEN_REG_SW_RESET, 818c2ecf20Sopenharmony_ci RT711_HIDDEN_REG_SW_RESET); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int rt711_calibration(struct rt711_priv *rt711) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci unsigned int val, loop = 0; 878c2ecf20Sopenharmony_ci struct device *dev; 888c2ecf20Sopenharmony_ci struct regmap *regmap = rt711->regmap; 898c2ecf20Sopenharmony_ci int ret = 0; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci mutex_lock(&rt711->calibrate_mutex); 928c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 938c2ecf20Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci dev = regmap_get_device(regmap); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Calibration manual mode */ 988c2ecf20Sopenharmony_ci rt711_index_update_bits(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, 998c2ecf20Sopenharmony_ci 0xf, 0x0); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* trigger */ 1028c2ecf20Sopenharmony_ci rt711_index_update_bits(regmap, RT711_VENDOR_CALI, 1038c2ecf20Sopenharmony_ci RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, 1048c2ecf20Sopenharmony_ci RT711_DAC_DC_CALI_TRIGGER); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* wait for calibration process */ 1078c2ecf20Sopenharmony_ci rt711_index_read(regmap, RT711_VENDOR_CALI, 1088c2ecf20Sopenharmony_ci RT711_DAC_DC_CALI_CTL1, &val); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci while (val & RT711_DAC_DC_CALI_TRIGGER) { 1118c2ecf20Sopenharmony_ci if (loop >= 500) { 1128c2ecf20Sopenharmony_ci pr_err("%s, calibration time-out!\n", 1138c2ecf20Sopenharmony_ci __func__); 1148c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci loop++; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 1208c2ecf20Sopenharmony_ci rt711_index_read(regmap, RT711_VENDOR_CALI, 1218c2ecf20Sopenharmony_ci RT711_DAC_DC_CALI_CTL1, &val); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* depop mode */ 1258c2ecf20Sopenharmony_ci rt711_index_update_bits(regmap, RT711_VENDOR_REG, 1268c2ecf20Sopenharmony_ci RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 1298c2ecf20Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 1308c2ecf20Sopenharmony_ci mutex_unlock(&rt711->calibrate_mutex); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret); 1338c2ecf20Sopenharmony_ci return ret; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic unsigned int rt711_button_detect(struct rt711_priv *rt711) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci unsigned int btn_type = 0, val80, val81; 1398c2ecf20Sopenharmony_ci int ret; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 1428c2ecf20Sopenharmony_ci RT711_IRQ_FLAG_TABLE1, &val80); 1438c2ecf20Sopenharmony_ci if (ret < 0) 1448c2ecf20Sopenharmony_ci goto read_error; 1458c2ecf20Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 1468c2ecf20Sopenharmony_ci RT711_IRQ_FLAG_TABLE2, &val81); 1478c2ecf20Sopenharmony_ci if (ret < 0) 1488c2ecf20Sopenharmony_ci goto read_error; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci val80 &= 0x0381; 1518c2ecf20Sopenharmony_ci val81 &= 0xff00; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci switch (val80) { 1548c2ecf20Sopenharmony_ci case 0x0200: 1558c2ecf20Sopenharmony_ci case 0x0100: 1568c2ecf20Sopenharmony_ci case 0x0080: 1578c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_0; 1588c2ecf20Sopenharmony_ci break; 1598c2ecf20Sopenharmony_ci case 0x0001: 1608c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_3; 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci switch (val81) { 1648c2ecf20Sopenharmony_ci case 0x8000: 1658c2ecf20Sopenharmony_ci case 0x4000: 1668c2ecf20Sopenharmony_ci case 0x2000: 1678c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_1; 1688c2ecf20Sopenharmony_ci break; 1698c2ecf20Sopenharmony_ci case 0x1000: 1708c2ecf20Sopenharmony_ci case 0x0800: 1718c2ecf20Sopenharmony_ci case 0x0400: 1728c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_2; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci case 0x0200: 1758c2ecf20Sopenharmony_ci case 0x0100: 1768c2ecf20Sopenharmony_ci btn_type |= SND_JACK_BTN_3; 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ciread_error: 1808c2ecf20Sopenharmony_ci return btn_type; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int rt711_headset_detect(struct rt711_priv *rt711) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci unsigned int buf, loop = 0; 1868c2ecf20Sopenharmony_ci int ret; 1878c2ecf20Sopenharmony_ci unsigned int jack_status = 0, reg; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 1908c2ecf20Sopenharmony_ci RT711_COMBO_JACK_AUTO_CTL2, &buf); 1918c2ecf20Sopenharmony_ci if (ret < 0) 1928c2ecf20Sopenharmony_ci goto io_error; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci while (loop < 500 && 1958c2ecf20Sopenharmony_ci (buf & RT711_COMBOJACK_AUTO_DET_STATUS) == 0) { 1968c2ecf20Sopenharmony_ci loop++; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci usleep_range(9000, 10000); 1998c2ecf20Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 2008c2ecf20Sopenharmony_ci RT711_COMBO_JACK_AUTO_CTL2, &buf); 2018c2ecf20Sopenharmony_ci if (ret < 0) 2028c2ecf20Sopenharmony_ci goto io_error; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; 2058c2ecf20Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &jack_status); 2068c2ecf20Sopenharmony_ci if (ret < 0) 2078c2ecf20Sopenharmony_ci goto io_error; 2088c2ecf20Sopenharmony_ci if ((jack_status & (1 << 31)) == 0) 2098c2ecf20Sopenharmony_ci goto remove_error; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (loop >= 500) 2138c2ecf20Sopenharmony_ci goto to_error; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (buf & RT711_COMBOJACK_AUTO_DET_TRS) 2168c2ecf20Sopenharmony_ci rt711->jack_type = SND_JACK_HEADPHONE; 2178c2ecf20Sopenharmony_ci else if ((buf & RT711_COMBOJACK_AUTO_DET_CTIA) || 2188c2ecf20Sopenharmony_ci (buf & RT711_COMBOJACK_AUTO_DET_OMTP)) 2198c2ecf20Sopenharmony_ci rt711->jack_type = SND_JACK_HEADSET; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cito_error: 2248c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 2258c2ecf20Sopenharmony_ci pr_err_ratelimited("Time-out error in %s\n", __func__); 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ciio_error: 2288c2ecf20Sopenharmony_ci pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ciremove_error: 2318c2ecf20Sopenharmony_ci pr_err_ratelimited("Jack removal in %s\n", __func__); 2328c2ecf20Sopenharmony_ci return -ENODEV; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic void rt711_jack_detect_handler(struct work_struct *work) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = 2388c2ecf20Sopenharmony_ci container_of(work, struct rt711_priv, jack_detect_work.work); 2398c2ecf20Sopenharmony_ci int btn_type = 0, ret; 2408c2ecf20Sopenharmony_ci unsigned int jack_status = 0, reg; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (!rt711->hs_jack) 2438c2ecf20Sopenharmony_ci return; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (!rt711->component->card->instantiated) 2468c2ecf20Sopenharmony_ci return; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; 2498c2ecf20Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &jack_status); 2508c2ecf20Sopenharmony_ci if (ret < 0) 2518c2ecf20Sopenharmony_ci goto io_error; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* pin attached */ 2548c2ecf20Sopenharmony_ci if (jack_status & (1 << 31)) { 2558c2ecf20Sopenharmony_ci /* jack in */ 2568c2ecf20Sopenharmony_ci if (rt711->jack_type == 0) { 2578c2ecf20Sopenharmony_ci ret = rt711_headset_detect(rt711); 2588c2ecf20Sopenharmony_ci if (ret < 0) 2598c2ecf20Sopenharmony_ci return; 2608c2ecf20Sopenharmony_ci if (rt711->jack_type == SND_JACK_HEADSET) 2618c2ecf20Sopenharmony_ci btn_type = rt711_button_detect(rt711); 2628c2ecf20Sopenharmony_ci } else if (rt711->jack_type == SND_JACK_HEADSET) { 2638c2ecf20Sopenharmony_ci /* jack is already in, report button event */ 2648c2ecf20Sopenharmony_ci btn_type = rt711_button_detect(rt711); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci } else { 2678c2ecf20Sopenharmony_ci /* jack out */ 2688c2ecf20Sopenharmony_ci rt711->jack_type = 0; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci dev_dbg(&rt711->slave->dev, 2728c2ecf20Sopenharmony_ci "in %s, jack_type=0x%x\n", __func__, rt711->jack_type); 2738c2ecf20Sopenharmony_ci dev_dbg(&rt711->slave->dev, 2748c2ecf20Sopenharmony_ci "in %s, btn_type=0x%x\n", __func__, btn_type); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type, 2778c2ecf20Sopenharmony_ci SND_JACK_HEADSET | 2788c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 2798c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (btn_type) { 2828c2ecf20Sopenharmony_ci /* button released */ 2838c2ecf20Sopenharmony_ci snd_soc_jack_report(rt711->hs_jack, rt711->jack_type, 2848c2ecf20Sopenharmony_ci SND_JACK_HEADSET | 2858c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 2868c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 2898c2ecf20Sopenharmony_ci &rt711->jack_btn_check_work, msecs_to_jiffies(200)); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciio_error: 2958c2ecf20Sopenharmony_ci pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic void rt711_btn_check_handler(struct work_struct *work) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = container_of(work, struct rt711_priv, 3018c2ecf20Sopenharmony_ci jack_btn_check_work.work); 3028c2ecf20Sopenharmony_ci int btn_type = 0, ret; 3038c2ecf20Sopenharmony_ci unsigned int jack_status = 0, reg; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; 3068c2ecf20Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &jack_status); 3078c2ecf20Sopenharmony_ci if (ret < 0) 3088c2ecf20Sopenharmony_ci goto io_error; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* pin attached */ 3118c2ecf20Sopenharmony_ci if (jack_status & (1 << 31)) { 3128c2ecf20Sopenharmony_ci if (rt711->jack_type == SND_JACK_HEADSET) { 3138c2ecf20Sopenharmony_ci /* jack is already in, report button event */ 3148c2ecf20Sopenharmony_ci btn_type = rt711_button_detect(rt711); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } else { 3178c2ecf20Sopenharmony_ci rt711->jack_type = 0; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* cbj comparator */ 3218c2ecf20Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 3228c2ecf20Sopenharmony_ci RT711_COMBO_JACK_AUTO_CTL2, ®); 3238c2ecf20Sopenharmony_ci if (ret < 0) 3248c2ecf20Sopenharmony_ci goto io_error; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if ((reg & 0xf0) == 0xf0) 3278c2ecf20Sopenharmony_ci btn_type = 0; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci dev_dbg(&rt711->slave->dev, 3308c2ecf20Sopenharmony_ci "%s, btn_type=0x%x\n", __func__, btn_type); 3318c2ecf20Sopenharmony_ci snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type, 3328c2ecf20Sopenharmony_ci SND_JACK_HEADSET | 3338c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 3348c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (btn_type) { 3378c2ecf20Sopenharmony_ci /* button released */ 3388c2ecf20Sopenharmony_ci snd_soc_jack_report(rt711->hs_jack, rt711->jack_type, 3398c2ecf20Sopenharmony_ci SND_JACK_HEADSET | 3408c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 3418c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 3448c2ecf20Sopenharmony_ci &rt711->jack_btn_check_work, msecs_to_jiffies(200)); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ciio_error: 3508c2ecf20Sopenharmony_ci pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic void rt711_jack_init(struct rt711_priv *rt711) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 3568c2ecf20Sopenharmony_ci snd_soc_component_get_dapm(rt711->component); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci mutex_lock(&rt711->calibrate_mutex); 3598c2ecf20Sopenharmony_ci /* power on */ 3608c2ecf20Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 3618c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 3628c2ecf20Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (rt711->hs_jack) { 3658c2ecf20Sopenharmony_ci /* unsolicited response & IRQ control */ 3668c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 3678c2ecf20Sopenharmony_ci RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82); 3688c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 3698c2ecf20Sopenharmony_ci RT711_SET_HP_UNSOLICITED_ENABLE, 0x81); 3708c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 3718c2ecf20Sopenharmony_ci RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83); 3728c2ecf20Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 3738c2ecf20Sopenharmony_ci 0x10, 0x2420); 3748c2ecf20Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 3758c2ecf20Sopenharmony_ci 0x19, 0x2e11); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci switch (rt711->jd_src) { 3788c2ecf20Sopenharmony_ci case RT711_JD1: 3798c2ecf20Sopenharmony_ci /* default settings was already for JD1 */ 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci case RT711_JD2: 3828c2ecf20Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 3838c2ecf20Sopenharmony_ci RT711_JD_CTL2, RT711_JD2_2PORT_200K_DECODE_HP | 3848c2ecf20Sopenharmony_ci RT711_HP_JD_SEL_JD2, 3858c2ecf20Sopenharmony_ci RT711_JD2_2PORT_200K_DECODE_HP | 3868c2ecf20Sopenharmony_ci RT711_HP_JD_SEL_JD2); 3878c2ecf20Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 3888c2ecf20Sopenharmony_ci RT711_CC_DET1, 3898c2ecf20Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12, 3908c2ecf20Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12); 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci case RT711_JD2_100K: 3938c2ecf20Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 3948c2ecf20Sopenharmony_ci RT711_JD_CTL2, RT711_JD2_2PORT_100K_DECODE | RT711_JD2_1PORT_TYPE_DECODE | 3958c2ecf20Sopenharmony_ci RT711_HP_JD_SEL_JD2 | RT711_JD1_2PORT_TYPE_100K_DECODE, 3968c2ecf20Sopenharmony_ci RT711_JD2_2PORT_100K_DECODE_HP | RT711_JD2_1PORT_JD_HP | 3978c2ecf20Sopenharmony_ci RT711_HP_JD_SEL_JD2 | RT711_JD1_2PORT_JD_RESERVED); 3988c2ecf20Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 3998c2ecf20Sopenharmony_ci RT711_CC_DET1, 4008c2ecf20Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12, 4018c2ecf20Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci case RT711_JD2_1P8V_1PORT: 4048c2ecf20Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 4058c2ecf20Sopenharmony_ci RT711_JD_CTL1, RT711_JD2_DIGITAL_JD_MODE_SEL, 4068c2ecf20Sopenharmony_ci RT711_JD2_1_JD_MODE); 4078c2ecf20Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 4088c2ecf20Sopenharmony_ci RT711_JD_CTL2, RT711_JD2_1PORT_TYPE_DECODE | 4098c2ecf20Sopenharmony_ci RT711_HP_JD_SEL_JD2, 4108c2ecf20Sopenharmony_ci RT711_JD2_1PORT_JD_HP | 4118c2ecf20Sopenharmony_ci RT711_HP_JD_SEL_JD2); 4128c2ecf20Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 4138c2ecf20Sopenharmony_ci RT711_JD_CTL4, RT711_JD2_PAD_PULL_UP_MASK | 4148c2ecf20Sopenharmony_ci RT711_JD2_MODE_SEL_MASK, 4158c2ecf20Sopenharmony_ci RT711_JD2_PAD_PULL_UP | 4168c2ecf20Sopenharmony_ci RT711_JD2_MODE2_1P8V_1PORT); 4178c2ecf20Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 4188c2ecf20Sopenharmony_ci RT711_CC_DET1, 4198c2ecf20Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12, 4208c2ecf20Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12); 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci default: 4238c2ecf20Sopenharmony_ci dev_warn(rt711->component->dev, "Wrong JD source\n"); 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci dev_dbg(&rt711->slave->dev, "in %s enable\n", __func__); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 4308c2ecf20Sopenharmony_ci &rt711->jack_detect_work, msecs_to_jiffies(250)); 4318c2ecf20Sopenharmony_ci } else { 4328c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 4338c2ecf20Sopenharmony_ci RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x00); 4348c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 4358c2ecf20Sopenharmony_ci RT711_SET_HP_UNSOLICITED_ENABLE, 0x00); 4368c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 4378c2ecf20Sopenharmony_ci RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x00); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__); 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* power off */ 4438c2ecf20Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 4448c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 4458c2ecf20Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 4468c2ecf20Sopenharmony_ci mutex_unlock(&rt711->calibrate_mutex); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int rt711_set_jack_detect(struct snd_soc_component *component, 4508c2ecf20Sopenharmony_ci struct snd_soc_jack *hs_jack, void *data) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci rt711->hs_jack = hs_jack; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (!rt711->hw_init) { 4578c2ecf20Sopenharmony_ci dev_dbg(&rt711->slave->dev, 4588c2ecf20Sopenharmony_ci "%s hw_init not ready yet\n", __func__); 4598c2ecf20Sopenharmony_ci return 0; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci rt711_jack_init(rt711); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void rt711_get_gain(struct rt711_priv *rt711, unsigned int addr_h, 4688c2ecf20Sopenharmony_ci unsigned int addr_l, unsigned int val_h, 4698c2ecf20Sopenharmony_ci unsigned int *r_val, unsigned int *l_val) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci /* R Channel */ 4728c2ecf20Sopenharmony_ci *r_val = (val_h << 8); 4738c2ecf20Sopenharmony_ci regmap_read(rt711->regmap, addr_l, r_val); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* L Channel */ 4768c2ecf20Sopenharmony_ci val_h |= 0x20; 4778c2ecf20Sopenharmony_ci *l_val = (val_h << 8); 4788c2ecf20Sopenharmony_ci regmap_read(rt711->regmap, addr_h, l_val); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/* For Verb-Set Amplifier Gain (Verb ID = 3h) */ 4828c2ecf20Sopenharmony_cistatic int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, 4838c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 4868c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 4878c2ecf20Sopenharmony_ci snd_soc_component_get_dapm(component); 4888c2ecf20Sopenharmony_ci struct soc_mixer_control *mc = 4898c2ecf20Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 4908c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 4918c2ecf20Sopenharmony_ci unsigned int addr_h, addr_l, val_h, val_ll, val_lr; 4928c2ecf20Sopenharmony_ci unsigned int read_ll, read_rl; 4938c2ecf20Sopenharmony_ci int i; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci mutex_lock(&rt711->calibrate_mutex); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* Can't use update bit function, so read the original value first */ 4988c2ecf20Sopenharmony_ci addr_h = mc->reg; 4998c2ecf20Sopenharmony_ci addr_l = mc->rreg; 5008c2ecf20Sopenharmony_ci if (mc->shift == RT711_DIR_OUT_SFT) /* output */ 5018c2ecf20Sopenharmony_ci val_h = 0x80; 5028c2ecf20Sopenharmony_ci else /* input */ 5038c2ecf20Sopenharmony_ci val_h = 0x0; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci rt711_get_gain(rt711, addr_h, addr_l, val_h, &read_rl, &read_ll); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* L Channel */ 5088c2ecf20Sopenharmony_ci if (mc->invert) { 5098c2ecf20Sopenharmony_ci /* for mute/unmute */ 5108c2ecf20Sopenharmony_ci val_ll = (mc->max - ucontrol->value.integer.value[0]) 5118c2ecf20Sopenharmony_ci << RT711_MUTE_SFT; 5128c2ecf20Sopenharmony_ci /* keep gain */ 5138c2ecf20Sopenharmony_ci read_ll = read_ll & 0x7f; 5148c2ecf20Sopenharmony_ci val_ll |= read_ll; 5158c2ecf20Sopenharmony_ci } else { 5168c2ecf20Sopenharmony_ci /* for gain */ 5178c2ecf20Sopenharmony_ci val_ll = ((ucontrol->value.integer.value[0]) & 0x7f); 5188c2ecf20Sopenharmony_ci if (val_ll > mc->max) 5198c2ecf20Sopenharmony_ci val_ll = mc->max; 5208c2ecf20Sopenharmony_ci /* keep mute status */ 5218c2ecf20Sopenharmony_ci read_ll = read_ll & (1 << RT711_MUTE_SFT); 5228c2ecf20Sopenharmony_ci val_ll |= read_ll; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 5268c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 5278c2ecf20Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* R Channel */ 5308c2ecf20Sopenharmony_ci if (mc->invert) { 5318c2ecf20Sopenharmony_ci /* for mute/unmute */ 5328c2ecf20Sopenharmony_ci val_lr = (mc->max - ucontrol->value.integer.value[1]) 5338c2ecf20Sopenharmony_ci << RT711_MUTE_SFT; 5348c2ecf20Sopenharmony_ci /* keep gain */ 5358c2ecf20Sopenharmony_ci read_rl = read_rl & 0x7f; 5368c2ecf20Sopenharmony_ci val_lr |= read_rl; 5378c2ecf20Sopenharmony_ci } else { 5388c2ecf20Sopenharmony_ci /* for gain */ 5398c2ecf20Sopenharmony_ci val_lr = ((ucontrol->value.integer.value[1]) & 0x7f); 5408c2ecf20Sopenharmony_ci if (val_lr > mc->max) 5418c2ecf20Sopenharmony_ci val_lr = mc->max; 5428c2ecf20Sopenharmony_ci /* keep mute status */ 5438c2ecf20Sopenharmony_ci read_rl = read_rl & (1 << RT711_MUTE_SFT); 5448c2ecf20Sopenharmony_ci val_lr |= read_rl; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { /* retry 3 times at most */ 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (val_ll == val_lr) { 5508c2ecf20Sopenharmony_ci /* Set both L/R channels at the same time */ 5518c2ecf20Sopenharmony_ci val_h = (1 << mc->shift) | (3 << 4); 5528c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 5538c2ecf20Sopenharmony_ci addr_h, (val_h << 8 | val_ll)); 5548c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 5558c2ecf20Sopenharmony_ci addr_l, (val_h << 8 | val_ll)); 5568c2ecf20Sopenharmony_ci } else { 5578c2ecf20Sopenharmony_ci /* Lch*/ 5588c2ecf20Sopenharmony_ci val_h = (1 << mc->shift) | (1 << 5); 5598c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 5608c2ecf20Sopenharmony_ci addr_h, (val_h << 8 | val_ll)); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Rch */ 5638c2ecf20Sopenharmony_ci val_h = (1 << mc->shift) | (1 << 4); 5648c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 5658c2ecf20Sopenharmony_ci addr_l, (val_h << 8 | val_lr)); 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci /* check result */ 5688c2ecf20Sopenharmony_ci if (mc->shift == RT711_DIR_OUT_SFT) /* output */ 5698c2ecf20Sopenharmony_ci val_h = 0x80; 5708c2ecf20Sopenharmony_ci else /* input */ 5718c2ecf20Sopenharmony_ci val_h = 0x0; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci rt711_get_gain(rt711, addr_h, addr_l, val_h, 5748c2ecf20Sopenharmony_ci &read_rl, &read_ll); 5758c2ecf20Sopenharmony_ci if (read_rl == val_lr && read_ll == val_ll) 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 5808c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 5818c2ecf20Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci mutex_unlock(&rt711->calibrate_mutex); 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic int rt711_set_amp_gain_get(struct snd_kcontrol *kcontrol, 5888c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 5918c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 5928c2ecf20Sopenharmony_ci struct soc_mixer_control *mc = 5938c2ecf20Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 5948c2ecf20Sopenharmony_ci unsigned int addr_h, addr_l, val_h; 5958c2ecf20Sopenharmony_ci unsigned int read_ll, read_rl; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* switch to get command */ 5988c2ecf20Sopenharmony_ci addr_h = mc->reg; 5998c2ecf20Sopenharmony_ci addr_l = mc->rreg; 6008c2ecf20Sopenharmony_ci if (mc->shift == RT711_DIR_OUT_SFT) /* output */ 6018c2ecf20Sopenharmony_ci val_h = 0x80; 6028c2ecf20Sopenharmony_ci else /* input */ 6038c2ecf20Sopenharmony_ci val_h = 0x0; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci rt711_get_gain(rt711, addr_h, addr_l, val_h, &read_rl, &read_ll); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (mc->invert) { 6088c2ecf20Sopenharmony_ci /* mute/unmute for switch controls */ 6098c2ecf20Sopenharmony_ci read_ll = !((read_ll & 0x80) >> RT711_MUTE_SFT); 6108c2ecf20Sopenharmony_ci read_rl = !((read_rl & 0x80) >> RT711_MUTE_SFT); 6118c2ecf20Sopenharmony_ci } else { 6128c2ecf20Sopenharmony_ci /* for gain volume controls */ 6138c2ecf20Sopenharmony_ci read_ll = read_ll & 0x7f; 6148c2ecf20Sopenharmony_ci read_rl = read_rl & 0x7f; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = read_ll; 6178c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = read_rl; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return 0; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); 6238c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); 6248c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new rt711_snd_controls[] = { 6278c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("DAC Surr Playback Volume", 6288c2ecf20Sopenharmony_ci RT711_SET_GAIN_DAC2_H, RT711_SET_GAIN_DAC2_L, 6298c2ecf20Sopenharmony_ci RT711_DIR_OUT_SFT, 0x57, 0, 6308c2ecf20Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, out_vol_tlv), 6318c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", 6328c2ecf20Sopenharmony_ci RT711_SET_GAIN_ADC2_H, RT711_SET_GAIN_ADC2_L, 6338c2ecf20Sopenharmony_ci RT711_DIR_IN_SFT, 1, 1, 6348c2ecf20Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put), 6358c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", 6368c2ecf20Sopenharmony_ci RT711_SET_GAIN_ADC1_H, RT711_SET_GAIN_ADC1_L, 6378c2ecf20Sopenharmony_ci RT711_DIR_IN_SFT, 1, 1, 6388c2ecf20Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put), 6398c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", 6408c2ecf20Sopenharmony_ci RT711_SET_GAIN_ADC2_H, RT711_SET_GAIN_ADC2_L, 6418c2ecf20Sopenharmony_ci RT711_DIR_IN_SFT, 0x3f, 0, 6428c2ecf20Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, in_vol_tlv), 6438c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", 6448c2ecf20Sopenharmony_ci RT711_SET_GAIN_ADC1_H, RT711_SET_GAIN_ADC1_L, 6458c2ecf20Sopenharmony_ci RT711_DIR_IN_SFT, 0x3f, 0, 6468c2ecf20Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, in_vol_tlv), 6478c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("AMIC Volume", 6488c2ecf20Sopenharmony_ci RT711_SET_GAIN_AMIC_H, RT711_SET_GAIN_AMIC_L, 6498c2ecf20Sopenharmony_ci RT711_DIR_IN_SFT, 3, 0, 6508c2ecf20Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv), 6518c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("DMIC1 Volume", 6528c2ecf20Sopenharmony_ci RT711_SET_GAIN_DMIC1_H, RT711_SET_GAIN_DMIC1_L, 6538c2ecf20Sopenharmony_ci RT711_DIR_IN_SFT, 3, 0, 6548c2ecf20Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv), 6558c2ecf20Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("DMIC2 Volume", 6568c2ecf20Sopenharmony_ci RT711_SET_GAIN_DMIC2_H, RT711_SET_GAIN_DMIC2_L, 6578c2ecf20Sopenharmony_ci RT711_DIR_IN_SFT, 3, 0, 6588c2ecf20Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv), 6598c2ecf20Sopenharmony_ci}; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic int rt711_mux_get(struct snd_kcontrol *kcontrol, 6628c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct snd_soc_component *component = 6658c2ecf20Sopenharmony_ci snd_soc_dapm_kcontrol_component(kcontrol); 6668c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 6678c2ecf20Sopenharmony_ci unsigned int reg, val = 0, nid; 6688c2ecf20Sopenharmony_ci int ret; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (strstr(ucontrol->id.name, "ADC 22 Mux")) 6718c2ecf20Sopenharmony_ci nid = RT711_MIXER_IN1; 6728c2ecf20Sopenharmony_ci else if (strstr(ucontrol->id.name, "ADC 23 Mux")) 6738c2ecf20Sopenharmony_ci nid = RT711_MIXER_IN2; 6748c2ecf20Sopenharmony_ci else 6758c2ecf20Sopenharmony_ci return -EINVAL; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* vid = 0xf01 */ 6788c2ecf20Sopenharmony_ci reg = RT711_VERB_SET_CONNECT_SEL | nid; 6798c2ecf20Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &val); 6808c2ecf20Sopenharmony_ci if (ret < 0) { 6818c2ecf20Sopenharmony_ci dev_err(component->dev, "%s: sdw read failed: %d\n", 6828c2ecf20Sopenharmony_ci __func__, ret); 6838c2ecf20Sopenharmony_ci return ret; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = val; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return 0; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic int rt711_mux_put(struct snd_kcontrol *kcontrol, 6928c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct snd_soc_component *component = 6958c2ecf20Sopenharmony_ci snd_soc_dapm_kcontrol_component(kcontrol); 6968c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 6978c2ecf20Sopenharmony_ci snd_soc_dapm_kcontrol_dapm(kcontrol); 6988c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 6998c2ecf20Sopenharmony_ci struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 7008c2ecf20Sopenharmony_ci unsigned int *item = ucontrol->value.enumerated.item; 7018c2ecf20Sopenharmony_ci unsigned int val, val2 = 0, change, reg, nid; 7028c2ecf20Sopenharmony_ci int ret; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (item[0] >= e->items) 7058c2ecf20Sopenharmony_ci return -EINVAL; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (strstr(ucontrol->id.name, "ADC 22 Mux")) 7088c2ecf20Sopenharmony_ci nid = RT711_MIXER_IN1; 7098c2ecf20Sopenharmony_ci else if (strstr(ucontrol->id.name, "ADC 23 Mux")) 7108c2ecf20Sopenharmony_ci nid = RT711_MIXER_IN2; 7118c2ecf20Sopenharmony_ci else 7128c2ecf20Sopenharmony_ci return -EINVAL; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Verb ID = 0x701h */ 7158c2ecf20Sopenharmony_ci val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci reg = RT711_VERB_SET_CONNECT_SEL | nid; 7188c2ecf20Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &val2); 7198c2ecf20Sopenharmony_ci if (ret < 0) { 7208c2ecf20Sopenharmony_ci dev_err(component->dev, "%s: sdw read failed: %d\n", 7218c2ecf20Sopenharmony_ci __func__, ret); 7228c2ecf20Sopenharmony_ci return ret; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if (val == val2) 7268c2ecf20Sopenharmony_ci change = 0; 7278c2ecf20Sopenharmony_ci else 7288c2ecf20Sopenharmony_ci change = 1; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (change) { 7318c2ecf20Sopenharmony_ci reg = RT711_VERB_SET_CONNECT_SEL | nid; 7328c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, reg, val); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci snd_soc_dapm_mux_update_power(dapm, kcontrol, 7368c2ecf20Sopenharmony_ci item[0], e, NULL); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return change; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic const char * const adc_mux_text[] = { 7428c2ecf20Sopenharmony_ci "MIC2", 7438c2ecf20Sopenharmony_ci "LINE1", 7448c2ecf20Sopenharmony_ci "LINE2", 7458c2ecf20Sopenharmony_ci "DMIC", 7468c2ecf20Sopenharmony_ci}; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 7498c2ecf20Sopenharmony_ci rt711_adc22_enum, SND_SOC_NOPM, 0, adc_mux_text); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 7528c2ecf20Sopenharmony_ci rt711_adc23_enum, SND_SOC_NOPM, 0, adc_mux_text); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new rt711_adc22_mux = 7558c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt711_adc22_enum, 7568c2ecf20Sopenharmony_ci rt711_mux_get, rt711_mux_put); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new rt711_adc23_mux = 7598c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt711_adc23_enum, 7608c2ecf20Sopenharmony_ci rt711_mux_get, rt711_mux_put); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic int rt711_dac_surround_event(struct snd_soc_dapm_widget *w, 7638c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct snd_soc_component *component = 7668c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 7678c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 7688c2ecf20Sopenharmony_ci unsigned int val_h = (1 << RT711_DIR_OUT_SFT) | (0x3 << 4); 7698c2ecf20Sopenharmony_ci unsigned int val_l; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci switch (event) { 7728c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 7738c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 7748c2ecf20Sopenharmony_ci RT711_SET_STREAMID_DAC2, 0x10); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci val_l = 0x00; 7778c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 7788c2ecf20Sopenharmony_ci RT711_SET_GAIN_HP_H, (val_h << 8 | val_l)); 7798c2ecf20Sopenharmony_ci break; 7808c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 7818c2ecf20Sopenharmony_ci val_l = (1 << RT711_MUTE_SFT); 7828c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 7838c2ecf20Sopenharmony_ci RT711_SET_GAIN_HP_H, (val_h << 8 | val_l)); 7848c2ecf20Sopenharmony_ci usleep_range(50000, 55000); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 7878c2ecf20Sopenharmony_ci RT711_SET_STREAMID_DAC2, 0x00); 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci return 0; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int rt711_adc_09_event(struct snd_soc_dapm_widget *w, 7948c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct snd_soc_component *component = 7978c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 7988c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci switch (event) { 8018c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 8028c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 8038c2ecf20Sopenharmony_ci RT711_SET_STREAMID_ADC1, 0x10); 8048c2ecf20Sopenharmony_ci break; 8058c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 8068c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 8078c2ecf20Sopenharmony_ci RT711_SET_STREAMID_ADC1, 0x00); 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci return 0; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic int rt711_adc_08_event(struct snd_soc_dapm_widget *w, 8148c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct snd_soc_component *component = 8178c2ecf20Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 8188c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci switch (event) { 8218c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 8228c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 8238c2ecf20Sopenharmony_ci RT711_SET_STREAMID_ADC2, 0x10); 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 8268c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 8278c2ecf20Sopenharmony_ci RT711_SET_STREAMID_ADC2, 0x00); 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci return 0; 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget rt711_dapm_widgets[] = { 8348c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HP"), 8358c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC2"), 8368c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("DMIC1"), 8378c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("DMIC2"), 8388c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("LINE1"), 8398c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("LINE2"), 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC Surround", NULL, SND_SOC_NOPM, 0, 0, 8428c2ecf20Sopenharmony_ci rt711_dac_surround_event, 8438c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 8448c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC_E("ADC 09", NULL, SND_SOC_NOPM, 0, 0, 8458c2ecf20Sopenharmony_ci rt711_adc_09_event, 8468c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 8478c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC_E("ADC 08", NULL, SND_SOC_NOPM, 0, 0, 8488c2ecf20Sopenharmony_ci rt711_adc_08_event, 8498c2ecf20Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 8508c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, 8518c2ecf20Sopenharmony_ci &rt711_adc22_mux), 8528c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, 8538c2ecf20Sopenharmony_ci &rt711_adc23_mux), 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), 8568c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0), 8578c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), 8588c2ecf20Sopenharmony_ci}; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route rt711_audio_map[] = { 8618c2ecf20Sopenharmony_ci {"DAC Surround", NULL, "DP3RX"}, 8628c2ecf20Sopenharmony_ci {"DP2TX", NULL, "ADC 09"}, 8638c2ecf20Sopenharmony_ci {"DP4TX", NULL, "ADC 08"}, 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci {"ADC 09", NULL, "ADC 22 Mux"}, 8668c2ecf20Sopenharmony_ci {"ADC 08", NULL, "ADC 23 Mux"}, 8678c2ecf20Sopenharmony_ci {"ADC 22 Mux", "DMIC", "DMIC1"}, 8688c2ecf20Sopenharmony_ci {"ADC 22 Mux", "LINE1", "LINE1"}, 8698c2ecf20Sopenharmony_ci {"ADC 22 Mux", "LINE2", "LINE2"}, 8708c2ecf20Sopenharmony_ci {"ADC 22 Mux", "MIC2", "MIC2"}, 8718c2ecf20Sopenharmony_ci {"ADC 23 Mux", "DMIC", "DMIC2"}, 8728c2ecf20Sopenharmony_ci {"ADC 23 Mux", "LINE1", "LINE1"}, 8738c2ecf20Sopenharmony_ci {"ADC 23 Mux", "LINE2", "LINE2"}, 8748c2ecf20Sopenharmony_ci {"ADC 23 Mux", "MIC2", "MIC2"}, 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci {"HP", NULL, "DAC Surround"}, 8778c2ecf20Sopenharmony_ci}; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_cistatic int rt711_set_bias_level(struct snd_soc_component *component, 8808c2ecf20Sopenharmony_ci enum snd_soc_bias_level level) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 8838c2ecf20Sopenharmony_ci snd_soc_component_get_dapm(component); 8848c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci switch (level) { 8878c2ecf20Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 8888c2ecf20Sopenharmony_ci if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { 8898c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 8908c2ecf20Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, 8918c2ecf20Sopenharmony_ci AC_PWRST_D0); 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci break; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 8968c2ecf20Sopenharmony_ci mutex_lock(&rt711->calibrate_mutex); 8978c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 8988c2ecf20Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, 8998c2ecf20Sopenharmony_ci AC_PWRST_D3); 9008c2ecf20Sopenharmony_ci mutex_unlock(&rt711->calibrate_mutex); 9018c2ecf20Sopenharmony_ci break; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci default: 9048c2ecf20Sopenharmony_ci break; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci return 0; 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_cistatic int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci device_property_read_u32(dev, "realtek,jd-src", 9138c2ecf20Sopenharmony_ci &rt711->jd_src); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci return 0; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic int rt711_probe(struct snd_soc_component *component) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci rt711_parse_dt(rt711, &rt711->slave->dev); 9238c2ecf20Sopenharmony_ci rt711->component = component; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return 0; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic void rt711_remove(struct snd_soc_component *component) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci regcache_cache_only(rt711->regmap, true); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver soc_codec_dev_rt711 = { 9368c2ecf20Sopenharmony_ci .probe = rt711_probe, 9378c2ecf20Sopenharmony_ci .set_bias_level = rt711_set_bias_level, 9388c2ecf20Sopenharmony_ci .controls = rt711_snd_controls, 9398c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(rt711_snd_controls), 9408c2ecf20Sopenharmony_ci .dapm_widgets = rt711_dapm_widgets, 9418c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(rt711_dapm_widgets), 9428c2ecf20Sopenharmony_ci .dapm_routes = rt711_audio_map, 9438c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(rt711_audio_map), 9448c2ecf20Sopenharmony_ci .set_jack = rt711_set_jack_detect, 9458c2ecf20Sopenharmony_ci .remove = rt711_remove, 9468c2ecf20Sopenharmony_ci}; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, 9498c2ecf20Sopenharmony_ci int direction) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci struct sdw_stream_data *stream; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (!sdw_stream) 9548c2ecf20Sopenharmony_ci return 0; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci stream = kzalloc(sizeof(*stream), GFP_KERNEL); 9578c2ecf20Sopenharmony_ci if (!stream) 9588c2ecf20Sopenharmony_ci return -ENOMEM; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci stream->sdw_stream = (struct sdw_stream_runtime *)sdw_stream; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ 9638c2ecf20Sopenharmony_ci if (direction == SNDRV_PCM_STREAM_PLAYBACK) 9648c2ecf20Sopenharmony_ci dai->playback_dma_data = stream; 9658c2ecf20Sopenharmony_ci else 9668c2ecf20Sopenharmony_ci dai->capture_dma_data = stream; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_cistatic void rt711_shutdown(struct snd_pcm_substream *substream, 9728c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci struct sdw_stream_data *stream; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci stream = snd_soc_dai_get_dma_data(dai, substream); 9778c2ecf20Sopenharmony_ci snd_soc_dai_set_dma_data(dai, substream, NULL); 9788c2ecf20Sopenharmony_ci kfree(stream); 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic int rt711_pcm_hw_params(struct snd_pcm_substream *substream, 9828c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 9838c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 9868c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 9878c2ecf20Sopenharmony_ci struct sdw_stream_config stream_config; 9888c2ecf20Sopenharmony_ci struct sdw_port_config port_config; 9898c2ecf20Sopenharmony_ci enum sdw_data_direction direction; 9908c2ecf20Sopenharmony_ci struct sdw_stream_data *stream; 9918c2ecf20Sopenharmony_ci int retval, port, num_channels; 9928c2ecf20Sopenharmony_ci unsigned int val = 0; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "%s %s", __func__, dai->name); 9958c2ecf20Sopenharmony_ci stream = snd_soc_dai_get_dma_data(dai, substream); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (!stream) 9988c2ecf20Sopenharmony_ci return -EINVAL; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (!rt711->slave) 10018c2ecf20Sopenharmony_ci return -EINVAL; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* SoundWire specific configuration */ 10048c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 10058c2ecf20Sopenharmony_ci direction = SDW_DATA_DIR_RX; 10068c2ecf20Sopenharmony_ci port = 3; 10078c2ecf20Sopenharmony_ci } else { 10088c2ecf20Sopenharmony_ci direction = SDW_DATA_DIR_TX; 10098c2ecf20Sopenharmony_ci if (dai->id == RT711_AIF1) 10108c2ecf20Sopenharmony_ci port = 4; 10118c2ecf20Sopenharmony_ci else if (dai->id == RT711_AIF2) 10128c2ecf20Sopenharmony_ci port = 2; 10138c2ecf20Sopenharmony_ci else 10148c2ecf20Sopenharmony_ci return -EINVAL; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci stream_config.frame_rate = params_rate(params); 10188c2ecf20Sopenharmony_ci stream_config.ch_count = params_channels(params); 10198c2ecf20Sopenharmony_ci stream_config.bps = snd_pcm_format_width(params_format(params)); 10208c2ecf20Sopenharmony_ci stream_config.direction = direction; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci num_channels = params_channels(params); 10238c2ecf20Sopenharmony_ci port_config.ch_mask = (1 << (num_channels)) - 1; 10248c2ecf20Sopenharmony_ci port_config.num = port; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci retval = sdw_stream_add_slave(rt711->slave, &stream_config, 10278c2ecf20Sopenharmony_ci &port_config, 1, stream->sdw_stream); 10288c2ecf20Sopenharmony_ci if (retval) { 10298c2ecf20Sopenharmony_ci dev_err(dai->dev, "Unable to configure port\n"); 10308c2ecf20Sopenharmony_ci return retval; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (params_channels(params) <= 16) { 10348c2ecf20Sopenharmony_ci /* bit 3:0 Number of Channel */ 10358c2ecf20Sopenharmony_ci val |= (params_channels(params) - 1); 10368c2ecf20Sopenharmony_ci } else { 10378c2ecf20Sopenharmony_ci dev_err(component->dev, "Unsupported channels %d\n", 10388c2ecf20Sopenharmony_ci params_channels(params)); 10398c2ecf20Sopenharmony_ci return -EINVAL; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci switch (params_width(params)) { 10438c2ecf20Sopenharmony_ci /* bit 6:4 Bits per Sample */ 10448c2ecf20Sopenharmony_ci case 8: 10458c2ecf20Sopenharmony_ci break; 10468c2ecf20Sopenharmony_ci case 16: 10478c2ecf20Sopenharmony_ci val |= (0x1 << 4); 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci case 20: 10508c2ecf20Sopenharmony_ci val |= (0x2 << 4); 10518c2ecf20Sopenharmony_ci break; 10528c2ecf20Sopenharmony_ci case 24: 10538c2ecf20Sopenharmony_ci val |= (0x3 << 4); 10548c2ecf20Sopenharmony_ci break; 10558c2ecf20Sopenharmony_ci case 32: 10568c2ecf20Sopenharmony_ci val |= (0x4 << 4); 10578c2ecf20Sopenharmony_ci break; 10588c2ecf20Sopenharmony_ci default: 10598c2ecf20Sopenharmony_ci return -EINVAL; 10608c2ecf20Sopenharmony_ci } 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* 48Khz */ 10638c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_DAC_FORMAT_H, val); 10648c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_ADC1_FORMAT_H, val); 10658c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_ADC2_FORMAT_H, val); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci return retval; 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_cistatic int rt711_pcm_hw_free(struct snd_pcm_substream *substream, 10718c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 10748c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 10758c2ecf20Sopenharmony_ci struct sdw_stream_data *stream = 10768c2ecf20Sopenharmony_ci snd_soc_dai_get_dma_data(dai, substream); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (!rt711->slave) 10798c2ecf20Sopenharmony_ci return -EINVAL; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci sdw_stream_remove_slave(rt711->slave, stream->sdw_stream); 10828c2ecf20Sopenharmony_ci return 0; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci#define RT711_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) 10868c2ecf20Sopenharmony_ci#define RT711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ 10878c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic struct snd_soc_dai_ops rt711_ops = { 10908c2ecf20Sopenharmony_ci .hw_params = rt711_pcm_hw_params, 10918c2ecf20Sopenharmony_ci .hw_free = rt711_pcm_hw_free, 10928c2ecf20Sopenharmony_ci .set_stream = rt711_set_sdw_stream, 10938c2ecf20Sopenharmony_ci .shutdown = rt711_shutdown, 10948c2ecf20Sopenharmony_ci}; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver rt711_dai[] = { 10978c2ecf20Sopenharmony_ci { 10988c2ecf20Sopenharmony_ci .name = "rt711-aif1", 10998c2ecf20Sopenharmony_ci .id = RT711_AIF1, 11008c2ecf20Sopenharmony_ci .playback = { 11018c2ecf20Sopenharmony_ci .stream_name = "DP3 Playback", 11028c2ecf20Sopenharmony_ci .channels_min = 1, 11038c2ecf20Sopenharmony_ci .channels_max = 2, 11048c2ecf20Sopenharmony_ci .rates = RT711_STEREO_RATES, 11058c2ecf20Sopenharmony_ci .formats = RT711_FORMATS, 11068c2ecf20Sopenharmony_ci }, 11078c2ecf20Sopenharmony_ci .capture = { 11088c2ecf20Sopenharmony_ci .stream_name = "DP4 Capture", 11098c2ecf20Sopenharmony_ci .channels_min = 1, 11108c2ecf20Sopenharmony_ci .channels_max = 2, 11118c2ecf20Sopenharmony_ci .rates = RT711_STEREO_RATES, 11128c2ecf20Sopenharmony_ci .formats = RT711_FORMATS, 11138c2ecf20Sopenharmony_ci }, 11148c2ecf20Sopenharmony_ci .ops = &rt711_ops, 11158c2ecf20Sopenharmony_ci }, 11168c2ecf20Sopenharmony_ci { 11178c2ecf20Sopenharmony_ci .name = "rt711-aif2", 11188c2ecf20Sopenharmony_ci .id = RT711_AIF2, 11198c2ecf20Sopenharmony_ci .capture = { 11208c2ecf20Sopenharmony_ci .stream_name = "DP2 Capture", 11218c2ecf20Sopenharmony_ci .channels_min = 1, 11228c2ecf20Sopenharmony_ci .channels_max = 2, 11238c2ecf20Sopenharmony_ci .rates = RT711_STEREO_RATES, 11248c2ecf20Sopenharmony_ci .formats = RT711_FORMATS, 11258c2ecf20Sopenharmony_ci }, 11268c2ecf20Sopenharmony_ci .ops = &rt711_ops, 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci}; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci/* Bus clock frequency */ 11318c2ecf20Sopenharmony_ci#define RT711_CLK_FREQ_9600000HZ 9600000 11328c2ecf20Sopenharmony_ci#define RT711_CLK_FREQ_12000000HZ 12000000 11338c2ecf20Sopenharmony_ci#define RT711_CLK_FREQ_6000000HZ 6000000 11348c2ecf20Sopenharmony_ci#define RT711_CLK_FREQ_4800000HZ 4800000 11358c2ecf20Sopenharmony_ci#define RT711_CLK_FREQ_2400000HZ 2400000 11368c2ecf20Sopenharmony_ci#define RT711_CLK_FREQ_12288000HZ 12288000 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ciint rt711_clock_config(struct device *dev) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(dev); 11418c2ecf20Sopenharmony_ci unsigned int clk_freq, value; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci clk_freq = (rt711->params.curr_dr_freq >> 1); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci switch (clk_freq) { 11468c2ecf20Sopenharmony_ci case RT711_CLK_FREQ_12000000HZ: 11478c2ecf20Sopenharmony_ci value = 0x0; 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci case RT711_CLK_FREQ_6000000HZ: 11508c2ecf20Sopenharmony_ci value = 0x1; 11518c2ecf20Sopenharmony_ci break; 11528c2ecf20Sopenharmony_ci case RT711_CLK_FREQ_9600000HZ: 11538c2ecf20Sopenharmony_ci value = 0x2; 11548c2ecf20Sopenharmony_ci break; 11558c2ecf20Sopenharmony_ci case RT711_CLK_FREQ_4800000HZ: 11568c2ecf20Sopenharmony_ci value = 0x3; 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci case RT711_CLK_FREQ_2400000HZ: 11598c2ecf20Sopenharmony_ci value = 0x4; 11608c2ecf20Sopenharmony_ci break; 11618c2ecf20Sopenharmony_ci case RT711_CLK_FREQ_12288000HZ: 11628c2ecf20Sopenharmony_ci value = 0x5; 11638c2ecf20Sopenharmony_ci break; 11648c2ecf20Sopenharmony_ci default: 11658c2ecf20Sopenharmony_ci return -EINVAL; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0xe0, value); 11698c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0xf0, value); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci return 0; 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic void rt711_calibration_work(struct work_struct *work) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = 11798c2ecf20Sopenharmony_ci container_of(work, struct rt711_priv, calibration_work); 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci rt711_calibration(rt711); 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ciint rt711_init(struct device *dev, struct regmap *sdw_regmap, 11858c2ecf20Sopenharmony_ci struct regmap *regmap, struct sdw_slave *slave) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci struct rt711_priv *rt711; 11888c2ecf20Sopenharmony_ci int ret; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci rt711 = devm_kzalloc(dev, sizeof(*rt711), GFP_KERNEL); 11918c2ecf20Sopenharmony_ci if (!rt711) 11928c2ecf20Sopenharmony_ci return -ENOMEM; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci dev_set_drvdata(dev, rt711); 11958c2ecf20Sopenharmony_ci rt711->slave = slave; 11968c2ecf20Sopenharmony_ci rt711->sdw_regmap = sdw_regmap; 11978c2ecf20Sopenharmony_ci rt711->regmap = regmap; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* 12008c2ecf20Sopenharmony_ci * Mark hw_init to false 12018c2ecf20Sopenharmony_ci * HW init will be performed when device reports present 12028c2ecf20Sopenharmony_ci */ 12038c2ecf20Sopenharmony_ci rt711->hw_init = false; 12048c2ecf20Sopenharmony_ci rt711->first_hw_init = false; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci /* JD source uses JD2 in default */ 12078c2ecf20Sopenharmony_ci rt711->jd_src = RT711_JD2; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(dev, 12108c2ecf20Sopenharmony_ci &soc_codec_dev_rt711, 12118c2ecf20Sopenharmony_ci rt711_dai, 12128c2ecf20Sopenharmony_ci ARRAY_SIZE(rt711_dai)); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci dev_dbg(&slave->dev, "%s\n", __func__); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci return ret; 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ciint rt711_io_init(struct device *dev, struct sdw_slave *slave) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(dev); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci if (rt711->hw_init) 12248c2ecf20Sopenharmony_ci return 0; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (rt711->first_hw_init) { 12278c2ecf20Sopenharmony_ci regcache_cache_only(rt711->regmap, false); 12288c2ecf20Sopenharmony_ci regcache_cache_bypass(rt711->regmap, true); 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci /* 12328c2ecf20Sopenharmony_ci * PM runtime is only enabled when a Slave reports as Attached 12338c2ecf20Sopenharmony_ci */ 12348c2ecf20Sopenharmony_ci if (!rt711->first_hw_init) { 12358c2ecf20Sopenharmony_ci /* set autosuspend parameters */ 12368c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&slave->dev, 3000); 12378c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&slave->dev); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* update count of parent 'active' children */ 12408c2ecf20Sopenharmony_ci pm_runtime_set_active(&slave->dev); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci /* make sure the device does not suspend immediately */ 12438c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(&slave->dev); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci pm_runtime_enable(&slave->dev); 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&slave->dev); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci rt711_reset(rt711->regmap); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci /* power on */ 12538c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /* Set Pin Widget */ 12568c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_MIC2, 0x25); 12578c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_HP, 0xc0); 12588c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_DMIC1, 0x20); 12598c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_DMIC2, 0x20); 12608c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_LINE1, 0x20); 12618c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_LINE2, 0x20); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* Mute HP/ADC1/ADC2 */ 12648c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_HP_H, 0xa080); 12658c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_HP_H, 0x9080); 12668c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_ADC2_H, 0x6080); 12678c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_ADC2_H, 0x5080); 12688c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_ADC1_H, 0x6080); 12698c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_ADC1_H, 0x5080); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci /* Set Configuration Default */ 12728c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4f12, 0x91); 12738c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4e12, 0xd6); 12748c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4d12, 0x11); 12758c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4c12, 0x20); 12768c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4f13, 0x91); 12778c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4e13, 0xd6); 12788c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4d13, 0x11); 12798c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4c13, 0x21); 12808c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4c21, 0xf0); 12818c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4d21, 0x11); 12828c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4e21, 0x11); 12838c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, 0x4f21, 0x01); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* Data port arrangement */ 12868c2ecf20Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 12878c2ecf20Sopenharmony_ci RT711_TX_RX_MUX_CTL, 0x0154); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci /* Set index */ 12908c2ecf20Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 12918c2ecf20Sopenharmony_ci RT711_DIGITAL_MISC_CTRL4, 0x201b); 12928c2ecf20Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 12938c2ecf20Sopenharmony_ci RT711_COMBO_JACK_AUTO_CTL1, 0x5089); 12948c2ecf20Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 12958c2ecf20Sopenharmony_ci RT711_VREFOUT_CTL, 0x5064); 12968c2ecf20Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 12978c2ecf20Sopenharmony_ci RT711_INLINE_CMD_CTL, 0xd249); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci /* Finish Initial Settings, set power to D3 */ 13008c2ecf20Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci if (rt711->first_hw_init) 13038c2ecf20Sopenharmony_ci rt711_calibration(rt711); 13048c2ecf20Sopenharmony_ci else { 13058c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&rt711->jack_detect_work, 13068c2ecf20Sopenharmony_ci rt711_jack_detect_handler); 13078c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&rt711->jack_btn_check_work, 13088c2ecf20Sopenharmony_ci rt711_btn_check_handler); 13098c2ecf20Sopenharmony_ci mutex_init(&rt711->calibrate_mutex); 13108c2ecf20Sopenharmony_ci INIT_WORK(&rt711->calibration_work, rt711_calibration_work); 13118c2ecf20Sopenharmony_ci schedule_work(&rt711->calibration_work); 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* 13158c2ecf20Sopenharmony_ci * if set_jack callback occurred early than io_init, 13168c2ecf20Sopenharmony_ci * we set up the jack detection function now 13178c2ecf20Sopenharmony_ci */ 13188c2ecf20Sopenharmony_ci if (rt711->hs_jack) 13198c2ecf20Sopenharmony_ci rt711_jack_init(rt711); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (rt711->first_hw_init) { 13228c2ecf20Sopenharmony_ci regcache_cache_bypass(rt711->regmap, false); 13238c2ecf20Sopenharmony_ci regcache_mark_dirty(rt711->regmap); 13248c2ecf20Sopenharmony_ci } else 13258c2ecf20Sopenharmony_ci rt711->first_hw_init = true; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci /* Mark Slave initialization complete */ 13288c2ecf20Sopenharmony_ci rt711->hw_init = true; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(&slave->dev); 13318c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(&slave->dev); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); 13348c2ecf20Sopenharmony_ci return 0; 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC RT711 SDW driver"); 13388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); 13398c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1340