162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// rt711.c -- rt711 ALSA SoC audio driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright(c) 2019 Realtek Semiconductor Corp. 662306a36Sopenharmony_ci// 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/moduleparam.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1562306a36Sopenharmony_ci#include <linux/pm.h> 1662306a36Sopenharmony_ci#include <linux/soundwire/sdw.h> 1762306a36Sopenharmony_ci#include <linux/regmap.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <sound/core.h> 2062306a36Sopenharmony_ci#include <sound/pcm.h> 2162306a36Sopenharmony_ci#include <sound/pcm_params.h> 2262306a36Sopenharmony_ci#include <sound/sdw.h> 2362306a36Sopenharmony_ci#include <sound/soc.h> 2462306a36Sopenharmony_ci#include <sound/soc-dapm.h> 2562306a36Sopenharmony_ci#include <sound/initval.h> 2662306a36Sopenharmony_ci#include <sound/tlv.h> 2762306a36Sopenharmony_ci#include <sound/hda_verbs.h> 2862306a36Sopenharmony_ci#include <sound/jack.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "rt711.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic int rt711_index_write(struct regmap *regmap, 3362306a36Sopenharmony_ci unsigned int nid, unsigned int reg, unsigned int value) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci int ret; 3662306a36Sopenharmony_ci unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 8) | reg; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci ret = regmap_write(regmap, addr, value); 3962306a36Sopenharmony_ci if (ret < 0) 4062306a36Sopenharmony_ci pr_err("Failed to set private value: %06x <= %04x ret=%d\n", 4162306a36Sopenharmony_ci addr, value, ret); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci return ret; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int rt711_index_read(struct regmap *regmap, 4762306a36Sopenharmony_ci unsigned int nid, unsigned int reg, unsigned int *value) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci int ret; 5062306a36Sopenharmony_ci unsigned int addr = ((RT711_PRIV_INDEX_W_H | nid) << 8) | reg; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci *value = 0; 5362306a36Sopenharmony_ci ret = regmap_read(regmap, addr, value); 5462306a36Sopenharmony_ci if (ret < 0) 5562306a36Sopenharmony_ci pr_err("Failed to get private value: %06x => %04x ret=%d\n", 5662306a36Sopenharmony_ci addr, *value, ret); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return ret; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int rt711_index_update_bits(struct regmap *regmap, unsigned int nid, 6262306a36Sopenharmony_ci unsigned int reg, unsigned int mask, unsigned int val) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci unsigned int tmp, orig; 6562306a36Sopenharmony_ci int ret; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ret = rt711_index_read(regmap, nid, reg, &orig); 6862306a36Sopenharmony_ci if (ret < 0) 6962306a36Sopenharmony_ci return ret; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci tmp = orig & ~mask; 7262306a36Sopenharmony_ci tmp |= val & mask; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci return rt711_index_write(regmap, nid, reg, tmp); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic void rt711_reset(struct regmap *regmap) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci regmap_write(regmap, RT711_FUNC_RESET, 0); 8062306a36Sopenharmony_ci rt711_index_update_bits(regmap, RT711_VENDOR_REG, 8162306a36Sopenharmony_ci RT711_PARA_VERB_CTL, RT711_HIDDEN_REG_SW_RESET, 8262306a36Sopenharmony_ci RT711_HIDDEN_REG_SW_RESET); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int rt711_calibration(struct rt711_priv *rt711) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci unsigned int val, loop = 0; 8862306a36Sopenharmony_ci struct device *dev; 8962306a36Sopenharmony_ci struct regmap *regmap = rt711->regmap; 9062306a36Sopenharmony_ci int ret = 0; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci mutex_lock(&rt711->calibrate_mutex); 9362306a36Sopenharmony_ci regmap_write(rt711->regmap, 9462306a36Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci dev = regmap_get_device(regmap); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* Calibration manual mode */ 9962306a36Sopenharmony_ci rt711_index_update_bits(regmap, RT711_VENDOR_REG, RT711_FSM_CTL, 10062306a36Sopenharmony_ci 0xf, 0x0); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* trigger */ 10362306a36Sopenharmony_ci rt711_index_update_bits(regmap, RT711_VENDOR_CALI, 10462306a36Sopenharmony_ci RT711_DAC_DC_CALI_CTL1, RT711_DAC_DC_CALI_TRIGGER, 10562306a36Sopenharmony_ci RT711_DAC_DC_CALI_TRIGGER); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* wait for calibration process */ 10862306a36Sopenharmony_ci rt711_index_read(regmap, RT711_VENDOR_CALI, 10962306a36Sopenharmony_ci RT711_DAC_DC_CALI_CTL1, &val); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci while (val & RT711_DAC_DC_CALI_TRIGGER) { 11262306a36Sopenharmony_ci if (loop >= 500) { 11362306a36Sopenharmony_ci pr_err("%s, calibration time-out!\n", 11462306a36Sopenharmony_ci __func__); 11562306a36Sopenharmony_ci ret = -ETIMEDOUT; 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci loop++; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci usleep_range(10000, 11000); 12162306a36Sopenharmony_ci rt711_index_read(regmap, RT711_VENDOR_CALI, 12262306a36Sopenharmony_ci RT711_DAC_DC_CALI_CTL1, &val); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* depop mode */ 12662306a36Sopenharmony_ci rt711_index_update_bits(regmap, RT711_VENDOR_REG, 12762306a36Sopenharmony_ci RT711_FSM_CTL, 0xf, RT711_DEPOP_CTL); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci regmap_write(rt711->regmap, 13062306a36Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 13162306a36Sopenharmony_ci mutex_unlock(&rt711->calibrate_mutex); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci dev_dbg(dev, "%s calibration complete, ret=%d\n", __func__, ret); 13462306a36Sopenharmony_ci return ret; 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic unsigned int rt711_button_detect(struct rt711_priv *rt711) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci unsigned int btn_type = 0, val80, val81; 14062306a36Sopenharmony_ci int ret; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 14362306a36Sopenharmony_ci RT711_IRQ_FLAG_TABLE1, &val80); 14462306a36Sopenharmony_ci if (ret < 0) 14562306a36Sopenharmony_ci goto read_error; 14662306a36Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 14762306a36Sopenharmony_ci RT711_IRQ_FLAG_TABLE2, &val81); 14862306a36Sopenharmony_ci if (ret < 0) 14962306a36Sopenharmony_ci goto read_error; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci val80 &= 0x0381; 15262306a36Sopenharmony_ci val81 &= 0xff00; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci switch (val80) { 15562306a36Sopenharmony_ci case 0x0200: 15662306a36Sopenharmony_ci case 0x0100: 15762306a36Sopenharmony_ci case 0x0080: 15862306a36Sopenharmony_ci btn_type |= SND_JACK_BTN_0; 15962306a36Sopenharmony_ci break; 16062306a36Sopenharmony_ci case 0x0001: 16162306a36Sopenharmony_ci btn_type |= SND_JACK_BTN_3; 16262306a36Sopenharmony_ci break; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci switch (val81) { 16562306a36Sopenharmony_ci case 0x8000: 16662306a36Sopenharmony_ci case 0x4000: 16762306a36Sopenharmony_ci case 0x2000: 16862306a36Sopenharmony_ci btn_type |= SND_JACK_BTN_1; 16962306a36Sopenharmony_ci break; 17062306a36Sopenharmony_ci case 0x1000: 17162306a36Sopenharmony_ci case 0x0800: 17262306a36Sopenharmony_ci case 0x0400: 17362306a36Sopenharmony_ci btn_type |= SND_JACK_BTN_2; 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci case 0x0200: 17662306a36Sopenharmony_ci case 0x0100: 17762306a36Sopenharmony_ci btn_type |= SND_JACK_BTN_3; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ciread_error: 18162306a36Sopenharmony_ci return btn_type; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int rt711_headset_detect(struct rt711_priv *rt711) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci unsigned int buf, loop = 0; 18762306a36Sopenharmony_ci int ret; 18862306a36Sopenharmony_ci unsigned int jack_status = 0, reg; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 19162306a36Sopenharmony_ci RT711_COMBO_JACK_AUTO_CTL2, &buf); 19262306a36Sopenharmony_ci if (ret < 0) 19362306a36Sopenharmony_ci goto io_error; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci while (loop < 500 && 19662306a36Sopenharmony_ci (buf & RT711_COMBOJACK_AUTO_DET_STATUS) == 0) { 19762306a36Sopenharmony_ci loop++; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci usleep_range(9000, 10000); 20062306a36Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 20162306a36Sopenharmony_ci RT711_COMBO_JACK_AUTO_CTL2, &buf); 20262306a36Sopenharmony_ci if (ret < 0) 20362306a36Sopenharmony_ci goto io_error; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; 20662306a36Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &jack_status); 20762306a36Sopenharmony_ci if (ret < 0) 20862306a36Sopenharmony_ci goto io_error; 20962306a36Sopenharmony_ci if ((jack_status & (1 << 31)) == 0) 21062306a36Sopenharmony_ci goto remove_error; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (loop >= 500) 21462306a36Sopenharmony_ci goto to_error; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (buf & RT711_COMBOJACK_AUTO_DET_TRS) 21762306a36Sopenharmony_ci rt711->jack_type = SND_JACK_HEADPHONE; 21862306a36Sopenharmony_ci else if ((buf & RT711_COMBOJACK_AUTO_DET_CTIA) || 21962306a36Sopenharmony_ci (buf & RT711_COMBOJACK_AUTO_DET_OMTP)) 22062306a36Sopenharmony_ci rt711->jack_type = SND_JACK_HEADSET; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return 0; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cito_error: 22562306a36Sopenharmony_ci ret = -ETIMEDOUT; 22662306a36Sopenharmony_ci pr_err_ratelimited("Time-out error in %s\n", __func__); 22762306a36Sopenharmony_ci return ret; 22862306a36Sopenharmony_ciio_error: 22962306a36Sopenharmony_ci pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ciremove_error: 23262306a36Sopenharmony_ci pr_err_ratelimited("Jack removal in %s\n", __func__); 23362306a36Sopenharmony_ci return -ENODEV; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void rt711_jack_detect_handler(struct work_struct *work) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct rt711_priv *rt711 = 23962306a36Sopenharmony_ci container_of(work, struct rt711_priv, jack_detect_work.work); 24062306a36Sopenharmony_ci int btn_type = 0, ret; 24162306a36Sopenharmony_ci unsigned int jack_status = 0, reg; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (!rt711->hs_jack) 24462306a36Sopenharmony_ci return; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (!snd_soc_card_is_instantiated(rt711->component->card)) 24762306a36Sopenharmony_ci return; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (pm_runtime_status_suspended(rt711->slave->dev.parent)) { 25062306a36Sopenharmony_ci dev_dbg(&rt711->slave->dev, 25162306a36Sopenharmony_ci "%s: parent device is pm_runtime_status_suspended, skipping jack detection\n", 25262306a36Sopenharmony_ci __func__); 25362306a36Sopenharmony_ci return; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; 25762306a36Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &jack_status); 25862306a36Sopenharmony_ci if (ret < 0) 25962306a36Sopenharmony_ci goto io_error; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* pin attached */ 26262306a36Sopenharmony_ci if (jack_status & (1 << 31)) { 26362306a36Sopenharmony_ci /* jack in */ 26462306a36Sopenharmony_ci if (rt711->jack_type == 0) { 26562306a36Sopenharmony_ci ret = rt711_headset_detect(rt711); 26662306a36Sopenharmony_ci if (ret < 0) 26762306a36Sopenharmony_ci return; 26862306a36Sopenharmony_ci if (rt711->jack_type == SND_JACK_HEADSET) 26962306a36Sopenharmony_ci btn_type = rt711_button_detect(rt711); 27062306a36Sopenharmony_ci } else if (rt711->jack_type == SND_JACK_HEADSET) { 27162306a36Sopenharmony_ci /* jack is already in, report button event */ 27262306a36Sopenharmony_ci btn_type = rt711_button_detect(rt711); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci } else { 27562306a36Sopenharmony_ci /* jack out */ 27662306a36Sopenharmony_ci rt711->jack_type = 0; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci dev_dbg(&rt711->slave->dev, 28062306a36Sopenharmony_ci "in %s, jack_type=0x%x\n", __func__, rt711->jack_type); 28162306a36Sopenharmony_ci dev_dbg(&rt711->slave->dev, 28262306a36Sopenharmony_ci "in %s, btn_type=0x%x\n", __func__, btn_type); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type, 28562306a36Sopenharmony_ci SND_JACK_HEADSET | 28662306a36Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 28762306a36Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (btn_type) { 29062306a36Sopenharmony_ci /* button released */ 29162306a36Sopenharmony_ci snd_soc_jack_report(rt711->hs_jack, rt711->jack_type, 29262306a36Sopenharmony_ci SND_JACK_HEADSET | 29362306a36Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 29462306a36Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 29762306a36Sopenharmony_ci &rt711->jack_btn_check_work, msecs_to_jiffies(200)); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ciio_error: 30362306a36Sopenharmony_ci pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void rt711_btn_check_handler(struct work_struct *work) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct rt711_priv *rt711 = container_of(work, struct rt711_priv, 30962306a36Sopenharmony_ci jack_btn_check_work.work); 31062306a36Sopenharmony_ci int btn_type = 0, ret; 31162306a36Sopenharmony_ci unsigned int jack_status = 0, reg; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci reg = RT711_VERB_GET_PIN_SENSE | RT711_HP_OUT; 31462306a36Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &jack_status); 31562306a36Sopenharmony_ci if (ret < 0) 31662306a36Sopenharmony_ci goto io_error; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* pin attached */ 31962306a36Sopenharmony_ci if (jack_status & (1 << 31)) { 32062306a36Sopenharmony_ci if (rt711->jack_type == SND_JACK_HEADSET) { 32162306a36Sopenharmony_ci /* jack is already in, report button event */ 32262306a36Sopenharmony_ci btn_type = rt711_button_detect(rt711); 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci } else { 32562306a36Sopenharmony_ci rt711->jack_type = 0; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* cbj comparator */ 32962306a36Sopenharmony_ci ret = rt711_index_read(rt711->regmap, RT711_VENDOR_REG, 33062306a36Sopenharmony_ci RT711_COMBO_JACK_AUTO_CTL2, ®); 33162306a36Sopenharmony_ci if (ret < 0) 33262306a36Sopenharmony_ci goto io_error; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if ((reg & 0xf0) == 0xf0) 33562306a36Sopenharmony_ci btn_type = 0; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci dev_dbg(&rt711->slave->dev, 33862306a36Sopenharmony_ci "%s, btn_type=0x%x\n", __func__, btn_type); 33962306a36Sopenharmony_ci snd_soc_jack_report(rt711->hs_jack, rt711->jack_type | btn_type, 34062306a36Sopenharmony_ci SND_JACK_HEADSET | 34162306a36Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 34262306a36Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (btn_type) { 34562306a36Sopenharmony_ci /* button released */ 34662306a36Sopenharmony_ci snd_soc_jack_report(rt711->hs_jack, rt711->jack_type, 34762306a36Sopenharmony_ci SND_JACK_HEADSET | 34862306a36Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 34962306a36Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 35262306a36Sopenharmony_ci &rt711->jack_btn_check_work, msecs_to_jiffies(200)); 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ciio_error: 35862306a36Sopenharmony_ci pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic void rt711_jack_init(struct rt711_priv *rt711) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = 36462306a36Sopenharmony_ci snd_soc_component_get_dapm(rt711->component); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci mutex_lock(&rt711->calibrate_mutex); 36762306a36Sopenharmony_ci /* power on */ 36862306a36Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 36962306a36Sopenharmony_ci regmap_write(rt711->regmap, 37062306a36Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (rt711->hs_jack) { 37362306a36Sopenharmony_ci /* unsolicited response & IRQ control */ 37462306a36Sopenharmony_ci regmap_write(rt711->regmap, 37562306a36Sopenharmony_ci RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x82); 37662306a36Sopenharmony_ci regmap_write(rt711->regmap, 37762306a36Sopenharmony_ci RT711_SET_HP_UNSOLICITED_ENABLE, 0x81); 37862306a36Sopenharmony_ci regmap_write(rt711->regmap, 37962306a36Sopenharmony_ci RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x83); 38062306a36Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 38162306a36Sopenharmony_ci 0x10, 0x2420); 38262306a36Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 38362306a36Sopenharmony_ci 0x19, 0x2e11); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci switch (rt711->jd_src) { 38662306a36Sopenharmony_ci case RT711_JD1: 38762306a36Sopenharmony_ci /* default settings was already for JD1 */ 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci case RT711_JD2: 39062306a36Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 39162306a36Sopenharmony_ci RT711_JD_CTL2, RT711_JD2_2PORT_200K_DECODE_HP | 39262306a36Sopenharmony_ci RT711_HP_JD_SEL_JD2, 39362306a36Sopenharmony_ci RT711_JD2_2PORT_200K_DECODE_HP | 39462306a36Sopenharmony_ci RT711_HP_JD_SEL_JD2); 39562306a36Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 39662306a36Sopenharmony_ci RT711_CC_DET1, 39762306a36Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12, 39862306a36Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12); 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci case RT711_JD2_100K: 40162306a36Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 40262306a36Sopenharmony_ci RT711_JD_CTL2, RT711_JD2_2PORT_100K_DECODE | RT711_JD2_1PORT_TYPE_DECODE | 40362306a36Sopenharmony_ci RT711_HP_JD_SEL_JD2 | RT711_JD1_2PORT_TYPE_100K_DECODE, 40462306a36Sopenharmony_ci RT711_JD2_2PORT_100K_DECODE_HP | RT711_JD2_1PORT_JD_HP | 40562306a36Sopenharmony_ci RT711_HP_JD_SEL_JD2 | RT711_JD1_2PORT_JD_RESERVED); 40662306a36Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 40762306a36Sopenharmony_ci RT711_CC_DET1, 40862306a36Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12, 40962306a36Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12); 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci case RT711_JD2_1P8V_1PORT: 41262306a36Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 41362306a36Sopenharmony_ci RT711_JD_CTL1, RT711_JD2_DIGITAL_JD_MODE_SEL, 41462306a36Sopenharmony_ci RT711_JD2_1_JD_MODE); 41562306a36Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 41662306a36Sopenharmony_ci RT711_JD_CTL2, RT711_JD2_1PORT_TYPE_DECODE | 41762306a36Sopenharmony_ci RT711_HP_JD_SEL_JD2, 41862306a36Sopenharmony_ci RT711_JD2_1PORT_JD_HP | 41962306a36Sopenharmony_ci RT711_HP_JD_SEL_JD2); 42062306a36Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 42162306a36Sopenharmony_ci RT711_JD_CTL4, RT711_JD2_PAD_PULL_UP_MASK | 42262306a36Sopenharmony_ci RT711_JD2_MODE_SEL_MASK, 42362306a36Sopenharmony_ci RT711_JD2_PAD_PULL_UP | 42462306a36Sopenharmony_ci RT711_JD2_MODE2_1P8V_1PORT); 42562306a36Sopenharmony_ci rt711_index_update_bits(rt711->regmap, RT711_VENDOR_REG, 42662306a36Sopenharmony_ci RT711_CC_DET1, 42762306a36Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12, 42862306a36Sopenharmony_ci RT711_HP_JD_FINAL_RESULT_CTL_JD12); 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci default: 43162306a36Sopenharmony_ci dev_warn(rt711->component->dev, "Wrong JD source\n"); 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci dev_dbg(&rt711->slave->dev, "in %s enable\n", __func__); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 43862306a36Sopenharmony_ci &rt711->jack_detect_work, msecs_to_jiffies(250)); 43962306a36Sopenharmony_ci } else { 44062306a36Sopenharmony_ci regmap_write(rt711->regmap, 44162306a36Sopenharmony_ci RT711_SET_MIC2_UNSOLICITED_ENABLE, 0x00); 44262306a36Sopenharmony_ci regmap_write(rt711->regmap, 44362306a36Sopenharmony_ci RT711_SET_HP_UNSOLICITED_ENABLE, 0x00); 44462306a36Sopenharmony_ci regmap_write(rt711->regmap, 44562306a36Sopenharmony_ci RT711_SET_INLINE_UNSOLICITED_ENABLE, 0x00); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci dev_dbg(&rt711->slave->dev, "in %s disable\n", __func__); 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* power off */ 45162306a36Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 45262306a36Sopenharmony_ci regmap_write(rt711->regmap, 45362306a36Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 45462306a36Sopenharmony_ci mutex_unlock(&rt711->calibrate_mutex); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic int rt711_set_jack_detect(struct snd_soc_component *component, 45862306a36Sopenharmony_ci struct snd_soc_jack *hs_jack, void *data) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 46162306a36Sopenharmony_ci int ret; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci rt711->hs_jack = hs_jack; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* we can only resume if the device was initialized at least once */ 46662306a36Sopenharmony_ci if (!rt711->first_hw_init) 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(component->dev); 47062306a36Sopenharmony_ci if (ret < 0) { 47162306a36Sopenharmony_ci if (ret != -EACCES) { 47262306a36Sopenharmony_ci dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret); 47362306a36Sopenharmony_ci return ret; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* pm_runtime not enabled yet */ 47762306a36Sopenharmony_ci dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__); 47862306a36Sopenharmony_ci return 0; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci rt711_jack_init(rt711); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci pm_runtime_mark_last_busy(component->dev); 48462306a36Sopenharmony_ci pm_runtime_put_autosuspend(component->dev); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic void rt711_get_gain(struct rt711_priv *rt711, unsigned int addr_h, 49062306a36Sopenharmony_ci unsigned int addr_l, unsigned int val_h, 49162306a36Sopenharmony_ci unsigned int *r_val, unsigned int *l_val) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci /* R Channel */ 49462306a36Sopenharmony_ci *r_val = (val_h << 8); 49562306a36Sopenharmony_ci regmap_read(rt711->regmap, addr_l, r_val); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* L Channel */ 49862306a36Sopenharmony_ci val_h |= 0x20; 49962306a36Sopenharmony_ci *l_val = (val_h << 8); 50062306a36Sopenharmony_ci regmap_read(rt711->regmap, addr_h, l_val); 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci/* For Verb-Set Amplifier Gain (Verb ID = 3h) */ 50462306a36Sopenharmony_cistatic int rt711_set_amp_gain_put(struct snd_kcontrol *kcontrol, 50562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 50862306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = 50962306a36Sopenharmony_ci snd_soc_component_get_dapm(component); 51062306a36Sopenharmony_ci struct soc_mixer_control *mc = 51162306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 51262306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 51362306a36Sopenharmony_ci unsigned int addr_h, addr_l, val_h, val_ll, val_lr; 51462306a36Sopenharmony_ci unsigned int read_ll, read_rl; 51562306a36Sopenharmony_ci int i; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci mutex_lock(&rt711->calibrate_mutex); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* Can't use update bit function, so read the original value first */ 52062306a36Sopenharmony_ci addr_h = mc->reg; 52162306a36Sopenharmony_ci addr_l = mc->rreg; 52262306a36Sopenharmony_ci if (mc->shift == RT711_DIR_OUT_SFT) /* output */ 52362306a36Sopenharmony_ci val_h = 0x80; 52462306a36Sopenharmony_ci else /* input */ 52562306a36Sopenharmony_ci val_h = 0x0; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci rt711_get_gain(rt711, addr_h, addr_l, val_h, &read_rl, &read_ll); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* L Channel */ 53062306a36Sopenharmony_ci if (mc->invert) { 53162306a36Sopenharmony_ci /* for mute/unmute */ 53262306a36Sopenharmony_ci val_ll = (mc->max - ucontrol->value.integer.value[0]) 53362306a36Sopenharmony_ci << RT711_MUTE_SFT; 53462306a36Sopenharmony_ci /* keep gain */ 53562306a36Sopenharmony_ci read_ll = read_ll & 0x7f; 53662306a36Sopenharmony_ci val_ll |= read_ll; 53762306a36Sopenharmony_ci } else { 53862306a36Sopenharmony_ci /* for gain */ 53962306a36Sopenharmony_ci val_ll = ((ucontrol->value.integer.value[0]) & 0x7f); 54062306a36Sopenharmony_ci if (val_ll > mc->max) 54162306a36Sopenharmony_ci val_ll = mc->max; 54262306a36Sopenharmony_ci /* keep mute status */ 54362306a36Sopenharmony_ci read_ll = read_ll & (1 << RT711_MUTE_SFT); 54462306a36Sopenharmony_ci val_ll |= read_ll; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 54862306a36Sopenharmony_ci regmap_write(rt711->regmap, 54962306a36Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* R Channel */ 55262306a36Sopenharmony_ci if (mc->invert) { 55362306a36Sopenharmony_ci /* for mute/unmute */ 55462306a36Sopenharmony_ci val_lr = (mc->max - ucontrol->value.integer.value[1]) 55562306a36Sopenharmony_ci << RT711_MUTE_SFT; 55662306a36Sopenharmony_ci /* keep gain */ 55762306a36Sopenharmony_ci read_rl = read_rl & 0x7f; 55862306a36Sopenharmony_ci val_lr |= read_rl; 55962306a36Sopenharmony_ci } else { 56062306a36Sopenharmony_ci /* for gain */ 56162306a36Sopenharmony_ci val_lr = ((ucontrol->value.integer.value[1]) & 0x7f); 56262306a36Sopenharmony_ci if (val_lr > mc->max) 56362306a36Sopenharmony_ci val_lr = mc->max; 56462306a36Sopenharmony_ci /* keep mute status */ 56562306a36Sopenharmony_ci read_rl = read_rl & (1 << RT711_MUTE_SFT); 56662306a36Sopenharmony_ci val_lr |= read_rl; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci for (i = 0; i < 3; i++) { /* retry 3 times at most */ 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (val_ll == val_lr) { 57262306a36Sopenharmony_ci /* Set both L/R channels at the same time */ 57362306a36Sopenharmony_ci val_h = (1 << mc->shift) | (3 << 4); 57462306a36Sopenharmony_ci regmap_write(rt711->regmap, 57562306a36Sopenharmony_ci addr_h, (val_h << 8 | val_ll)); 57662306a36Sopenharmony_ci regmap_write(rt711->regmap, 57762306a36Sopenharmony_ci addr_l, (val_h << 8 | val_ll)); 57862306a36Sopenharmony_ci } else { 57962306a36Sopenharmony_ci /* Lch*/ 58062306a36Sopenharmony_ci val_h = (1 << mc->shift) | (1 << 5); 58162306a36Sopenharmony_ci regmap_write(rt711->regmap, 58262306a36Sopenharmony_ci addr_h, (val_h << 8 | val_ll)); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Rch */ 58562306a36Sopenharmony_ci val_h = (1 << mc->shift) | (1 << 4); 58662306a36Sopenharmony_ci regmap_write(rt711->regmap, 58762306a36Sopenharmony_ci addr_l, (val_h << 8 | val_lr)); 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci /* check result */ 59062306a36Sopenharmony_ci if (mc->shift == RT711_DIR_OUT_SFT) /* output */ 59162306a36Sopenharmony_ci val_h = 0x80; 59262306a36Sopenharmony_ci else /* input */ 59362306a36Sopenharmony_ci val_h = 0x0; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci rt711_get_gain(rt711, addr_h, addr_l, val_h, 59662306a36Sopenharmony_ci &read_rl, &read_ll); 59762306a36Sopenharmony_ci if (read_rl == val_lr && read_ll == val_ll) 59862306a36Sopenharmony_ci break; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (dapm->bias_level <= SND_SOC_BIAS_STANDBY) 60262306a36Sopenharmony_ci regmap_write(rt711->regmap, 60362306a36Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci mutex_unlock(&rt711->calibrate_mutex); 60662306a36Sopenharmony_ci return 0; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int rt711_set_amp_gain_get(struct snd_kcontrol *kcontrol, 61062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); 61362306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 61462306a36Sopenharmony_ci struct soc_mixer_control *mc = 61562306a36Sopenharmony_ci (struct soc_mixer_control *)kcontrol->private_value; 61662306a36Sopenharmony_ci unsigned int addr_h, addr_l, val_h; 61762306a36Sopenharmony_ci unsigned int read_ll, read_rl; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* switch to get command */ 62062306a36Sopenharmony_ci addr_h = mc->reg; 62162306a36Sopenharmony_ci addr_l = mc->rreg; 62262306a36Sopenharmony_ci if (mc->shift == RT711_DIR_OUT_SFT) /* output */ 62362306a36Sopenharmony_ci val_h = 0x80; 62462306a36Sopenharmony_ci else /* input */ 62562306a36Sopenharmony_ci val_h = 0x0; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci rt711_get_gain(rt711, addr_h, addr_l, val_h, &read_rl, &read_ll); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (mc->invert) { 63062306a36Sopenharmony_ci /* mute/unmute for switch controls */ 63162306a36Sopenharmony_ci read_ll = !((read_ll & 0x80) >> RT711_MUTE_SFT); 63262306a36Sopenharmony_ci read_rl = !((read_rl & 0x80) >> RT711_MUTE_SFT); 63362306a36Sopenharmony_ci } else { 63462306a36Sopenharmony_ci /* for gain volume controls */ 63562306a36Sopenharmony_ci read_ll = read_ll & 0x7f; 63662306a36Sopenharmony_ci read_rl = read_rl & 0x7f; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = read_ll; 63962306a36Sopenharmony_ci ucontrol->value.integer.value[1] = read_rl; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); 64562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0); 64662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic const struct snd_kcontrol_new rt711_snd_controls[] = { 64962306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("DAC Surr Playback Volume", 65062306a36Sopenharmony_ci RT711_SET_GAIN_DAC2_H, RT711_SET_GAIN_DAC2_L, 65162306a36Sopenharmony_ci RT711_DIR_OUT_SFT, 0x57, 0, 65262306a36Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, out_vol_tlv), 65362306a36Sopenharmony_ci SOC_DOUBLE_R_EXT("ADC 08 Capture Switch", 65462306a36Sopenharmony_ci RT711_SET_GAIN_ADC2_H, RT711_SET_GAIN_ADC2_L, 65562306a36Sopenharmony_ci RT711_DIR_IN_SFT, 1, 1, 65662306a36Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put), 65762306a36Sopenharmony_ci SOC_DOUBLE_R_EXT("ADC 09 Capture Switch", 65862306a36Sopenharmony_ci RT711_SET_GAIN_ADC1_H, RT711_SET_GAIN_ADC1_L, 65962306a36Sopenharmony_ci RT711_DIR_IN_SFT, 1, 1, 66062306a36Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put), 66162306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume", 66262306a36Sopenharmony_ci RT711_SET_GAIN_ADC2_H, RT711_SET_GAIN_ADC2_L, 66362306a36Sopenharmony_ci RT711_DIR_IN_SFT, 0x3f, 0, 66462306a36Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, in_vol_tlv), 66562306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume", 66662306a36Sopenharmony_ci RT711_SET_GAIN_ADC1_H, RT711_SET_GAIN_ADC1_L, 66762306a36Sopenharmony_ci RT711_DIR_IN_SFT, 0x3f, 0, 66862306a36Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, in_vol_tlv), 66962306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("AMIC Volume", 67062306a36Sopenharmony_ci RT711_SET_GAIN_AMIC_H, RT711_SET_GAIN_AMIC_L, 67162306a36Sopenharmony_ci RT711_DIR_IN_SFT, 3, 0, 67262306a36Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv), 67362306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("DMIC1 Volume", 67462306a36Sopenharmony_ci RT711_SET_GAIN_DMIC1_H, RT711_SET_GAIN_DMIC1_L, 67562306a36Sopenharmony_ci RT711_DIR_IN_SFT, 3, 0, 67662306a36Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv), 67762306a36Sopenharmony_ci SOC_DOUBLE_R_EXT_TLV("DMIC2 Volume", 67862306a36Sopenharmony_ci RT711_SET_GAIN_DMIC2_H, RT711_SET_GAIN_DMIC2_L, 67962306a36Sopenharmony_ci RT711_DIR_IN_SFT, 3, 0, 68062306a36Sopenharmony_ci rt711_set_amp_gain_get, rt711_set_amp_gain_put, mic_vol_tlv), 68162306a36Sopenharmony_ci}; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int rt711_mux_get(struct snd_kcontrol *kcontrol, 68462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct snd_soc_component *component = 68762306a36Sopenharmony_ci snd_soc_dapm_kcontrol_component(kcontrol); 68862306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 68962306a36Sopenharmony_ci unsigned int reg, val = 0, nid; 69062306a36Sopenharmony_ci int ret; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci if (strstr(ucontrol->id.name, "ADC 22 Mux")) 69362306a36Sopenharmony_ci nid = RT711_MIXER_IN1; 69462306a36Sopenharmony_ci else if (strstr(ucontrol->id.name, "ADC 23 Mux")) 69562306a36Sopenharmony_ci nid = RT711_MIXER_IN2; 69662306a36Sopenharmony_ci else 69762306a36Sopenharmony_ci return -EINVAL; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* vid = 0xf01 */ 70062306a36Sopenharmony_ci reg = RT711_VERB_SET_CONNECT_SEL | nid; 70162306a36Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &val); 70262306a36Sopenharmony_ci if (ret < 0) { 70362306a36Sopenharmony_ci dev_err(component->dev, "%s: sdw read failed: %d\n", 70462306a36Sopenharmony_ci __func__, ret); 70562306a36Sopenharmony_ci return ret; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = val; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic int rt711_mux_put(struct snd_kcontrol *kcontrol, 71462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci struct snd_soc_component *component = 71762306a36Sopenharmony_ci snd_soc_dapm_kcontrol_component(kcontrol); 71862306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = 71962306a36Sopenharmony_ci snd_soc_dapm_kcontrol_dapm(kcontrol); 72062306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 72162306a36Sopenharmony_ci struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 72262306a36Sopenharmony_ci unsigned int *item = ucontrol->value.enumerated.item; 72362306a36Sopenharmony_ci unsigned int val, val2 = 0, change, reg, nid; 72462306a36Sopenharmony_ci int ret; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (item[0] >= e->items) 72762306a36Sopenharmony_ci return -EINVAL; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (strstr(ucontrol->id.name, "ADC 22 Mux")) 73062306a36Sopenharmony_ci nid = RT711_MIXER_IN1; 73162306a36Sopenharmony_ci else if (strstr(ucontrol->id.name, "ADC 23 Mux")) 73262306a36Sopenharmony_ci nid = RT711_MIXER_IN2; 73362306a36Sopenharmony_ci else 73462306a36Sopenharmony_ci return -EINVAL; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Verb ID = 0x701h */ 73762306a36Sopenharmony_ci val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci reg = RT711_VERB_SET_CONNECT_SEL | nid; 74062306a36Sopenharmony_ci ret = regmap_read(rt711->regmap, reg, &val2); 74162306a36Sopenharmony_ci if (ret < 0) { 74262306a36Sopenharmony_ci dev_err(component->dev, "%s: sdw read failed: %d\n", 74362306a36Sopenharmony_ci __func__, ret); 74462306a36Sopenharmony_ci return ret; 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (val == val2) 74862306a36Sopenharmony_ci change = 0; 74962306a36Sopenharmony_ci else 75062306a36Sopenharmony_ci change = 1; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (change) { 75362306a36Sopenharmony_ci reg = RT711_VERB_SET_CONNECT_SEL | nid; 75462306a36Sopenharmony_ci regmap_write(rt711->regmap, reg, val); 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci snd_soc_dapm_mux_update_power(dapm, kcontrol, 75862306a36Sopenharmony_ci item[0], e, NULL); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return change; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic const char * const adc_mux_text[] = { 76462306a36Sopenharmony_ci "MIC2", 76562306a36Sopenharmony_ci "LINE1", 76662306a36Sopenharmony_ci "LINE2", 76762306a36Sopenharmony_ci "DMIC", 76862306a36Sopenharmony_ci}; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 77162306a36Sopenharmony_ci rt711_adc22_enum, SND_SOC_NOPM, 0, adc_mux_text); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 77462306a36Sopenharmony_ci rt711_adc23_enum, SND_SOC_NOPM, 0, adc_mux_text); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic const struct snd_kcontrol_new rt711_adc22_mux = 77762306a36Sopenharmony_ci SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt711_adc22_enum, 77862306a36Sopenharmony_ci rt711_mux_get, rt711_mux_put); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic const struct snd_kcontrol_new rt711_adc23_mux = 78162306a36Sopenharmony_ci SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt711_adc23_enum, 78262306a36Sopenharmony_ci rt711_mux_get, rt711_mux_put); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_cistatic int rt711_dac_surround_event(struct snd_soc_dapm_widget *w, 78562306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci struct snd_soc_component *component = 78862306a36Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 78962306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 79062306a36Sopenharmony_ci unsigned int val_h = (1 << RT711_DIR_OUT_SFT) | (0x3 << 4); 79162306a36Sopenharmony_ci unsigned int val_l; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci switch (event) { 79462306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 79562306a36Sopenharmony_ci regmap_write(rt711->regmap, 79662306a36Sopenharmony_ci RT711_SET_STREAMID_DAC2, 0x10); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci val_l = 0x00; 79962306a36Sopenharmony_ci regmap_write(rt711->regmap, 80062306a36Sopenharmony_ci RT711_SET_GAIN_HP_H, (val_h << 8 | val_l)); 80162306a36Sopenharmony_ci break; 80262306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 80362306a36Sopenharmony_ci val_l = (1 << RT711_MUTE_SFT); 80462306a36Sopenharmony_ci regmap_write(rt711->regmap, 80562306a36Sopenharmony_ci RT711_SET_GAIN_HP_H, (val_h << 8 | val_l)); 80662306a36Sopenharmony_ci usleep_range(50000, 55000); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci regmap_write(rt711->regmap, 80962306a36Sopenharmony_ci RT711_SET_STREAMID_DAC2, 0x00); 81062306a36Sopenharmony_ci break; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic int rt711_adc_09_event(struct snd_soc_dapm_widget *w, 81662306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct snd_soc_component *component = 81962306a36Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 82062306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci switch (event) { 82362306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 82462306a36Sopenharmony_ci regmap_write(rt711->regmap, 82562306a36Sopenharmony_ci RT711_SET_STREAMID_ADC1, 0x10); 82662306a36Sopenharmony_ci break; 82762306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 82862306a36Sopenharmony_ci regmap_write(rt711->regmap, 82962306a36Sopenharmony_ci RT711_SET_STREAMID_ADC1, 0x00); 83062306a36Sopenharmony_ci break; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci return 0; 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cistatic int rt711_adc_08_event(struct snd_soc_dapm_widget *w, 83662306a36Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci struct snd_soc_component *component = 83962306a36Sopenharmony_ci snd_soc_dapm_to_component(w->dapm); 84062306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci switch (event) { 84362306a36Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 84462306a36Sopenharmony_ci regmap_write(rt711->regmap, 84562306a36Sopenharmony_ci RT711_SET_STREAMID_ADC2, 0x10); 84662306a36Sopenharmony_ci break; 84762306a36Sopenharmony_ci case SND_SOC_DAPM_PRE_PMD: 84862306a36Sopenharmony_ci regmap_write(rt711->regmap, 84962306a36Sopenharmony_ci RT711_SET_STREAMID_ADC2, 0x00); 85062306a36Sopenharmony_ci break; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci return 0; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget rt711_dapm_widgets[] = { 85662306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HP"), 85762306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("MIC2"), 85862306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("DMIC1"), 85962306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("DMIC2"), 86062306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("LINE1"), 86162306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("LINE2"), 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC Surround", NULL, SND_SOC_NOPM, 0, 0, 86462306a36Sopenharmony_ci rt711_dac_surround_event, 86562306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 86662306a36Sopenharmony_ci SND_SOC_DAPM_ADC_E("ADC 09", NULL, SND_SOC_NOPM, 0, 0, 86762306a36Sopenharmony_ci rt711_adc_09_event, 86862306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 86962306a36Sopenharmony_ci SND_SOC_DAPM_ADC_E("ADC 08", NULL, SND_SOC_NOPM, 0, 0, 87062306a36Sopenharmony_ci rt711_adc_08_event, 87162306a36Sopenharmony_ci SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), 87262306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0, 87362306a36Sopenharmony_ci &rt711_adc22_mux), 87462306a36Sopenharmony_ci SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0, 87562306a36Sopenharmony_ci &rt711_adc23_mux), 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0), 87862306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0), 87962306a36Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0), 88062306a36Sopenharmony_ci}; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic const struct snd_soc_dapm_route rt711_audio_map[] = { 88362306a36Sopenharmony_ci {"DAC Surround", NULL, "DP3RX"}, 88462306a36Sopenharmony_ci {"DP2TX", NULL, "ADC 09"}, 88562306a36Sopenharmony_ci {"DP4TX", NULL, "ADC 08"}, 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci {"ADC 09", NULL, "ADC 22 Mux"}, 88862306a36Sopenharmony_ci {"ADC 08", NULL, "ADC 23 Mux"}, 88962306a36Sopenharmony_ci {"ADC 22 Mux", "DMIC", "DMIC1"}, 89062306a36Sopenharmony_ci {"ADC 22 Mux", "LINE1", "LINE1"}, 89162306a36Sopenharmony_ci {"ADC 22 Mux", "LINE2", "LINE2"}, 89262306a36Sopenharmony_ci {"ADC 22 Mux", "MIC2", "MIC2"}, 89362306a36Sopenharmony_ci {"ADC 23 Mux", "DMIC", "DMIC2"}, 89462306a36Sopenharmony_ci {"ADC 23 Mux", "LINE1", "LINE1"}, 89562306a36Sopenharmony_ci {"ADC 23 Mux", "LINE2", "LINE2"}, 89662306a36Sopenharmony_ci {"ADC 23 Mux", "MIC2", "MIC2"}, 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci {"HP", NULL, "DAC Surround"}, 89962306a36Sopenharmony_ci}; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic int rt711_set_bias_level(struct snd_soc_component *component, 90262306a36Sopenharmony_ci enum snd_soc_bias_level level) 90362306a36Sopenharmony_ci{ 90462306a36Sopenharmony_ci struct snd_soc_dapm_context *dapm = 90562306a36Sopenharmony_ci snd_soc_component_get_dapm(component); 90662306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci switch (level) { 90962306a36Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 91062306a36Sopenharmony_ci if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { 91162306a36Sopenharmony_ci regmap_write(rt711->regmap, 91262306a36Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, 91362306a36Sopenharmony_ci AC_PWRST_D0); 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci break; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 91862306a36Sopenharmony_ci mutex_lock(&rt711->calibrate_mutex); 91962306a36Sopenharmony_ci regmap_write(rt711->regmap, 92062306a36Sopenharmony_ci RT711_SET_AUDIO_POWER_STATE, 92162306a36Sopenharmony_ci AC_PWRST_D3); 92262306a36Sopenharmony_ci mutex_unlock(&rt711->calibrate_mutex); 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci default: 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci return 0; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cistatic int rt711_parse_dt(struct rt711_priv *rt711, struct device *dev) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci device_property_read_u32(dev, "realtek,jd-src", 93562306a36Sopenharmony_ci &rt711->jd_src); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci return 0; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int rt711_probe(struct snd_soc_component *component) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 94362306a36Sopenharmony_ci int ret; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci rt711_parse_dt(rt711, &rt711->slave->dev); 94662306a36Sopenharmony_ci rt711->component = component; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (!rt711->first_hw_init) 94962306a36Sopenharmony_ci return 0; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci ret = pm_runtime_resume(component->dev); 95262306a36Sopenharmony_ci if (ret < 0 && ret != -EACCES) 95362306a36Sopenharmony_ci return ret; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci return 0; 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_codec_dev_rt711 = { 95962306a36Sopenharmony_ci .probe = rt711_probe, 96062306a36Sopenharmony_ci .set_bias_level = rt711_set_bias_level, 96162306a36Sopenharmony_ci .controls = rt711_snd_controls, 96262306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(rt711_snd_controls), 96362306a36Sopenharmony_ci .dapm_widgets = rt711_dapm_widgets, 96462306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(rt711_dapm_widgets), 96562306a36Sopenharmony_ci .dapm_routes = rt711_audio_map, 96662306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(rt711_audio_map), 96762306a36Sopenharmony_ci .set_jack = rt711_set_jack_detect, 96862306a36Sopenharmony_ci .endianness = 1, 96962306a36Sopenharmony_ci}; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, 97262306a36Sopenharmony_ci int direction) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci snd_soc_dai_dma_data_set(dai, direction, sdw_stream); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci return 0; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic void rt711_shutdown(struct snd_pcm_substream *substream, 98062306a36Sopenharmony_ci struct snd_soc_dai *dai) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci snd_soc_dai_set_dma_data(dai, substream, NULL); 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_cistatic int rt711_pcm_hw_params(struct snd_pcm_substream *substream, 98662306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 98762306a36Sopenharmony_ci struct snd_soc_dai *dai) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 99062306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 99162306a36Sopenharmony_ci struct sdw_stream_config stream_config = {0}; 99262306a36Sopenharmony_ci struct sdw_port_config port_config = {0}; 99362306a36Sopenharmony_ci struct sdw_stream_runtime *sdw_stream; 99462306a36Sopenharmony_ci int retval; 99562306a36Sopenharmony_ci unsigned int val = 0; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci dev_dbg(dai->dev, "%s %s", __func__, dai->name); 99862306a36Sopenharmony_ci sdw_stream = snd_soc_dai_get_dma_data(dai, substream); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (!sdw_stream) 100162306a36Sopenharmony_ci return -EINVAL; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (!rt711->slave) 100462306a36Sopenharmony_ci return -EINVAL; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci /* SoundWire specific configuration */ 100762306a36Sopenharmony_ci snd_sdw_params_to_config(substream, params, &stream_config, &port_config); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 101062306a36Sopenharmony_ci port_config.num = 3; 101162306a36Sopenharmony_ci } else { 101262306a36Sopenharmony_ci if (dai->id == RT711_AIF1) 101362306a36Sopenharmony_ci port_config.num = 4; 101462306a36Sopenharmony_ci else if (dai->id == RT711_AIF2) 101562306a36Sopenharmony_ci port_config.num = 2; 101662306a36Sopenharmony_ci else 101762306a36Sopenharmony_ci return -EINVAL; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci retval = sdw_stream_add_slave(rt711->slave, &stream_config, 102162306a36Sopenharmony_ci &port_config, 1, sdw_stream); 102262306a36Sopenharmony_ci if (retval) { 102362306a36Sopenharmony_ci dev_err(dai->dev, "Unable to configure port\n"); 102462306a36Sopenharmony_ci return retval; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci if (params_channels(params) <= 16) { 102862306a36Sopenharmony_ci /* bit 3:0 Number of Channel */ 102962306a36Sopenharmony_ci val |= (params_channels(params) - 1); 103062306a36Sopenharmony_ci } else { 103162306a36Sopenharmony_ci dev_err(component->dev, "Unsupported channels %d\n", 103262306a36Sopenharmony_ci params_channels(params)); 103362306a36Sopenharmony_ci return -EINVAL; 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci switch (params_width(params)) { 103762306a36Sopenharmony_ci /* bit 6:4 Bits per Sample */ 103862306a36Sopenharmony_ci case 8: 103962306a36Sopenharmony_ci break; 104062306a36Sopenharmony_ci case 16: 104162306a36Sopenharmony_ci val |= (0x1 << 4); 104262306a36Sopenharmony_ci break; 104362306a36Sopenharmony_ci case 20: 104462306a36Sopenharmony_ci val |= (0x2 << 4); 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci case 24: 104762306a36Sopenharmony_ci val |= (0x3 << 4); 104862306a36Sopenharmony_ci break; 104962306a36Sopenharmony_ci case 32: 105062306a36Sopenharmony_ci val |= (0x4 << 4); 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci default: 105362306a36Sopenharmony_ci return -EINVAL; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* 48Khz */ 105762306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_DAC_FORMAT_H, val); 105862306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_ADC1_FORMAT_H, val); 105962306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_ADC2_FORMAT_H, val); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci return retval; 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic int rt711_pcm_hw_free(struct snd_pcm_substream *substream, 106562306a36Sopenharmony_ci struct snd_soc_dai *dai) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 106862306a36Sopenharmony_ci struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component); 106962306a36Sopenharmony_ci struct sdw_stream_runtime *sdw_stream = 107062306a36Sopenharmony_ci snd_soc_dai_get_dma_data(dai, substream); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci if (!rt711->slave) 107362306a36Sopenharmony_ci return -EINVAL; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci sdw_stream_remove_slave(rt711->slave, sdw_stream); 107662306a36Sopenharmony_ci return 0; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci#define RT711_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) 108062306a36Sopenharmony_ci#define RT711_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ 108162306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic const struct snd_soc_dai_ops rt711_ops = { 108462306a36Sopenharmony_ci .hw_params = rt711_pcm_hw_params, 108562306a36Sopenharmony_ci .hw_free = rt711_pcm_hw_free, 108662306a36Sopenharmony_ci .set_stream = rt711_set_sdw_stream, 108762306a36Sopenharmony_ci .shutdown = rt711_shutdown, 108862306a36Sopenharmony_ci}; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cistatic struct snd_soc_dai_driver rt711_dai[] = { 109162306a36Sopenharmony_ci { 109262306a36Sopenharmony_ci .name = "rt711-aif1", 109362306a36Sopenharmony_ci .id = RT711_AIF1, 109462306a36Sopenharmony_ci .playback = { 109562306a36Sopenharmony_ci .stream_name = "DP3 Playback", 109662306a36Sopenharmony_ci .channels_min = 1, 109762306a36Sopenharmony_ci .channels_max = 2, 109862306a36Sopenharmony_ci .rates = RT711_STEREO_RATES, 109962306a36Sopenharmony_ci .formats = RT711_FORMATS, 110062306a36Sopenharmony_ci }, 110162306a36Sopenharmony_ci .capture = { 110262306a36Sopenharmony_ci .stream_name = "DP4 Capture", 110362306a36Sopenharmony_ci .channels_min = 1, 110462306a36Sopenharmony_ci .channels_max = 2, 110562306a36Sopenharmony_ci .rates = RT711_STEREO_RATES, 110662306a36Sopenharmony_ci .formats = RT711_FORMATS, 110762306a36Sopenharmony_ci }, 110862306a36Sopenharmony_ci .ops = &rt711_ops, 110962306a36Sopenharmony_ci }, 111062306a36Sopenharmony_ci { 111162306a36Sopenharmony_ci .name = "rt711-aif2", 111262306a36Sopenharmony_ci .id = RT711_AIF2, 111362306a36Sopenharmony_ci .capture = { 111462306a36Sopenharmony_ci .stream_name = "DP2 Capture", 111562306a36Sopenharmony_ci .channels_min = 1, 111662306a36Sopenharmony_ci .channels_max = 2, 111762306a36Sopenharmony_ci .rates = RT711_STEREO_RATES, 111862306a36Sopenharmony_ci .formats = RT711_FORMATS, 111962306a36Sopenharmony_ci }, 112062306a36Sopenharmony_ci .ops = &rt711_ops, 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci}; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci/* Bus clock frequency */ 112562306a36Sopenharmony_ci#define RT711_CLK_FREQ_9600000HZ 9600000 112662306a36Sopenharmony_ci#define RT711_CLK_FREQ_12000000HZ 12000000 112762306a36Sopenharmony_ci#define RT711_CLK_FREQ_6000000HZ 6000000 112862306a36Sopenharmony_ci#define RT711_CLK_FREQ_4800000HZ 4800000 112962306a36Sopenharmony_ci#define RT711_CLK_FREQ_2400000HZ 2400000 113062306a36Sopenharmony_ci#define RT711_CLK_FREQ_12288000HZ 12288000 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ciint rt711_clock_config(struct device *dev) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(dev); 113562306a36Sopenharmony_ci unsigned int clk_freq, value; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci clk_freq = (rt711->params.curr_dr_freq >> 1); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci switch (clk_freq) { 114062306a36Sopenharmony_ci case RT711_CLK_FREQ_12000000HZ: 114162306a36Sopenharmony_ci value = 0x0; 114262306a36Sopenharmony_ci break; 114362306a36Sopenharmony_ci case RT711_CLK_FREQ_6000000HZ: 114462306a36Sopenharmony_ci value = 0x1; 114562306a36Sopenharmony_ci break; 114662306a36Sopenharmony_ci case RT711_CLK_FREQ_9600000HZ: 114762306a36Sopenharmony_ci value = 0x2; 114862306a36Sopenharmony_ci break; 114962306a36Sopenharmony_ci case RT711_CLK_FREQ_4800000HZ: 115062306a36Sopenharmony_ci value = 0x3; 115162306a36Sopenharmony_ci break; 115262306a36Sopenharmony_ci case RT711_CLK_FREQ_2400000HZ: 115362306a36Sopenharmony_ci value = 0x4; 115462306a36Sopenharmony_ci break; 115562306a36Sopenharmony_ci case RT711_CLK_FREQ_12288000HZ: 115662306a36Sopenharmony_ci value = 0x5; 115762306a36Sopenharmony_ci break; 115862306a36Sopenharmony_ci default: 115962306a36Sopenharmony_ci return -EINVAL; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci regmap_write(rt711->regmap, 0xe0, value); 116362306a36Sopenharmony_ci regmap_write(rt711->regmap, 0xf0, value); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci return 0; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic void rt711_calibration_work(struct work_struct *work) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct rt711_priv *rt711 = 117362306a36Sopenharmony_ci container_of(work, struct rt711_priv, calibration_work); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci rt711_calibration(rt711); 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ciint rt711_init(struct device *dev, struct regmap *sdw_regmap, 117962306a36Sopenharmony_ci struct regmap *regmap, struct sdw_slave *slave) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci struct rt711_priv *rt711; 118262306a36Sopenharmony_ci int ret; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci rt711 = devm_kzalloc(dev, sizeof(*rt711), GFP_KERNEL); 118562306a36Sopenharmony_ci if (!rt711) 118662306a36Sopenharmony_ci return -ENOMEM; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci dev_set_drvdata(dev, rt711); 118962306a36Sopenharmony_ci rt711->slave = slave; 119062306a36Sopenharmony_ci rt711->sdw_regmap = sdw_regmap; 119162306a36Sopenharmony_ci rt711->regmap = regmap; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci regcache_cache_only(rt711->regmap, true); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci mutex_init(&rt711->calibrate_mutex); 119662306a36Sopenharmony_ci mutex_init(&rt711->disable_irq_lock); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_jack_detect_handler); 119962306a36Sopenharmony_ci INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_btn_check_handler); 120062306a36Sopenharmony_ci INIT_WORK(&rt711->calibration_work, rt711_calibration_work); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* 120362306a36Sopenharmony_ci * Mark hw_init to false 120462306a36Sopenharmony_ci * HW init will be performed when device reports present 120562306a36Sopenharmony_ci */ 120662306a36Sopenharmony_ci rt711->hw_init = false; 120762306a36Sopenharmony_ci rt711->first_hw_init = false; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci /* JD source uses JD2 in default */ 121062306a36Sopenharmony_ci rt711->jd_src = RT711_JD2; 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, 121362306a36Sopenharmony_ci &soc_codec_dev_rt711, 121462306a36Sopenharmony_ci rt711_dai, 121562306a36Sopenharmony_ci ARRAY_SIZE(rt711_dai)); 121662306a36Sopenharmony_ci if (ret < 0) 121762306a36Sopenharmony_ci return ret; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci /* set autosuspend parameters */ 122062306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 3000); 122162306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci /* make sure the device does not suspend immediately */ 122462306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci pm_runtime_enable(dev); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci /* important note: the device is NOT tagged as 'active' and will remain 122962306a36Sopenharmony_ci * 'suspended' until the hardware is enumerated/initialized. This is required 123062306a36Sopenharmony_ci * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently 123162306a36Sopenharmony_ci * fail with -EACCESS because of race conditions between card creation and enumeration 123262306a36Sopenharmony_ci */ 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci dev_dbg(dev, "%s\n", __func__); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci return ret; 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ciint rt711_io_init(struct device *dev, struct sdw_slave *slave) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(dev); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci rt711->disable_irq = false; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if (rt711->hw_init) 124662306a36Sopenharmony_ci return 0; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci regcache_cache_only(rt711->regmap, false); 124962306a36Sopenharmony_ci if (rt711->first_hw_init) 125062306a36Sopenharmony_ci regcache_cache_bypass(rt711->regmap, true); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci /* 125362306a36Sopenharmony_ci * PM runtime status is marked as 'active' only when a Slave reports as Attached 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_ci if (!rt711->first_hw_init) 125662306a36Sopenharmony_ci /* update count of parent 'active' children */ 125762306a36Sopenharmony_ci pm_runtime_set_active(&slave->dev); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci pm_runtime_get_noresume(&slave->dev); 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci rt711_reset(rt711->regmap); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci /* power on */ 126462306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D0); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* Set Pin Widget */ 126762306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_MIC2, 0x25); 126862306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_HP, 0xc0); 126962306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_DMIC1, 0x20); 127062306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_DMIC2, 0x20); 127162306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_LINE1, 0x20); 127262306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_PIN_LINE2, 0x20); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci /* Mute HP/ADC1/ADC2 */ 127562306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_HP_H, 0xa080); 127662306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_HP_H, 0x9080); 127762306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_ADC2_H, 0x6080); 127862306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_ADC2_H, 0x5080); 127962306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_ADC1_H, 0x6080); 128062306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_GAIN_ADC1_H, 0x5080); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci /* Set Configuration Default */ 128362306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4f12, 0x91); 128462306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4e12, 0xd6); 128562306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4d12, 0x11); 128662306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4c12, 0x20); 128762306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4f13, 0x91); 128862306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4e13, 0xd6); 128962306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4d13, 0x11); 129062306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4c13, 0x21); 129162306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4c21, 0xf0); 129262306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4d21, 0x11); 129362306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4e21, 0x11); 129462306a36Sopenharmony_ci regmap_write(rt711->regmap, 0x4f21, 0x01); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci /* Data port arrangement */ 129762306a36Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 129862306a36Sopenharmony_ci RT711_TX_RX_MUX_CTL, 0x0154); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci /* Set index */ 130162306a36Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 130262306a36Sopenharmony_ci RT711_DIGITAL_MISC_CTRL4, 0x201b); 130362306a36Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 130462306a36Sopenharmony_ci RT711_COMBO_JACK_AUTO_CTL1, 0x5089); 130562306a36Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 130662306a36Sopenharmony_ci RT711_VREFOUT_CTL, 0x5064); 130762306a36Sopenharmony_ci rt711_index_write(rt711->regmap, RT711_VENDOR_REG, 130862306a36Sopenharmony_ci RT711_INLINE_CMD_CTL, 0xd249); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci /* Finish Initial Settings, set power to D3 */ 131162306a36Sopenharmony_ci regmap_write(rt711->regmap, RT711_SET_AUDIO_POWER_STATE, AC_PWRST_D3); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci if (rt711->first_hw_init) 131462306a36Sopenharmony_ci rt711_calibration(rt711); 131562306a36Sopenharmony_ci else 131662306a36Sopenharmony_ci schedule_work(&rt711->calibration_work); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci /* 131962306a36Sopenharmony_ci * if set_jack callback occurred early than io_init, 132062306a36Sopenharmony_ci * we set up the jack detection function now 132162306a36Sopenharmony_ci */ 132262306a36Sopenharmony_ci if (rt711->hs_jack) 132362306a36Sopenharmony_ci rt711_jack_init(rt711); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci if (rt711->first_hw_init) { 132662306a36Sopenharmony_ci regcache_cache_bypass(rt711->regmap, false); 132762306a36Sopenharmony_ci regcache_mark_dirty(rt711->regmap); 132862306a36Sopenharmony_ci } else 132962306a36Sopenharmony_ci rt711->first_hw_init = true; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci /* Mark Slave initialization complete */ 133262306a36Sopenharmony_ci rt711->hw_init = true; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci pm_runtime_mark_last_busy(&slave->dev); 133562306a36Sopenharmony_ci pm_runtime_put_autosuspend(&slave->dev); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci dev_dbg(&slave->dev, "%s hw_init complete\n", __func__); 133862306a36Sopenharmony_ci return 0; 133962306a36Sopenharmony_ci} 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC RT711 SDW driver"); 134262306a36Sopenharmony_ciMODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); 134362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1344