17d2a5f9aSShuming Fan // SPDX-License-Identifier: GPL-2.0
27d2a5f9aSShuming Fan //
37d2a5f9aSShuming Fan // rt700.c -- rt700 ALSA SoC audio driver
47d2a5f9aSShuming Fan //
57d2a5f9aSShuming Fan // Copyright(c) 2019 Realtek Semiconductor Corp.
67d2a5f9aSShuming Fan //
77d2a5f9aSShuming Fan //
87d2a5f9aSShuming Fan
97d2a5f9aSShuming Fan #include <linux/module.h>
107d2a5f9aSShuming Fan #include <linux/moduleparam.h>
117d2a5f9aSShuming Fan #include <linux/kernel.h>
127d2a5f9aSShuming Fan #include <linux/init.h>
137d2a5f9aSShuming Fan #include <linux/delay.h>
147d2a5f9aSShuming Fan #include <linux/pm_runtime.h>
157d2a5f9aSShuming Fan #include <linux/pm.h>
167d2a5f9aSShuming Fan #include <linux/soundwire/sdw.h>
177d2a5f9aSShuming Fan #include <linux/regmap.h>
187d2a5f9aSShuming Fan #include <linux/slab.h>
197d2a5f9aSShuming Fan #include <sound/core.h>
207d2a5f9aSShuming Fan #include <sound/pcm.h>
217d2a5f9aSShuming Fan #include <sound/pcm_params.h>
22ae7ad90eSCharles Keepax #include <sound/sdw.h>
237d2a5f9aSShuming Fan #include <sound/soc.h>
247d2a5f9aSShuming Fan #include <sound/soc-dapm.h>
257d2a5f9aSShuming Fan #include <sound/initval.h>
267d2a5f9aSShuming Fan #include <sound/tlv.h>
277d2a5f9aSShuming Fan #include <sound/hda_verbs.h>
287d2a5f9aSShuming Fan #include <sound/jack.h>
297d2a5f9aSShuming Fan
307d2a5f9aSShuming Fan #include "rt700.h"
317d2a5f9aSShuming Fan
rt700_index_write(struct regmap * regmap,unsigned int reg,unsigned int value)327d2a5f9aSShuming Fan static int rt700_index_write(struct regmap *regmap,
337d2a5f9aSShuming Fan unsigned int reg, unsigned int value)
347d2a5f9aSShuming Fan {
357d2a5f9aSShuming Fan int ret;
367d2a5f9aSShuming Fan unsigned int addr = (RT700_PRIV_INDEX_W_H << 8) | reg;
377d2a5f9aSShuming Fan
387d2a5f9aSShuming Fan ret = regmap_write(regmap, addr, value);
397d2a5f9aSShuming Fan if (ret < 0)
407d2a5f9aSShuming Fan pr_err("Failed to set private value: %06x <= %04x ret=%d\n",
417d2a5f9aSShuming Fan addr, value, ret);
427d2a5f9aSShuming Fan
437d2a5f9aSShuming Fan return ret;
447d2a5f9aSShuming Fan }
457d2a5f9aSShuming Fan
rt700_index_read(struct regmap * regmap,unsigned int reg,unsigned int * value)467d2a5f9aSShuming Fan static int rt700_index_read(struct regmap *regmap,
477d2a5f9aSShuming Fan unsigned int reg, unsigned int *value)
487d2a5f9aSShuming Fan {
497d2a5f9aSShuming Fan int ret;
507d2a5f9aSShuming Fan unsigned int addr = (RT700_PRIV_INDEX_W_H << 8) | reg;
517d2a5f9aSShuming Fan
527d2a5f9aSShuming Fan *value = 0;
537d2a5f9aSShuming Fan ret = regmap_read(regmap, addr, value);
547d2a5f9aSShuming Fan if (ret < 0)
557d2a5f9aSShuming Fan pr_err("Failed to get private value: %06x => %04x ret=%d\n",
567d2a5f9aSShuming Fan addr, *value, ret);
577d2a5f9aSShuming Fan
587d2a5f9aSShuming Fan return ret;
597d2a5f9aSShuming Fan }
607d2a5f9aSShuming Fan
rt700_button_detect(struct rt700_priv * rt700)617d2a5f9aSShuming Fan static unsigned int rt700_button_detect(struct rt700_priv *rt700)
627d2a5f9aSShuming Fan {
637d2a5f9aSShuming Fan unsigned int btn_type = 0, val80, val81;
647d2a5f9aSShuming Fan int ret;
657d2a5f9aSShuming Fan
667d2a5f9aSShuming Fan ret = rt700_index_read(rt700->regmap, RT700_IRQ_FLAG_TABLE1, &val80);
677d2a5f9aSShuming Fan if (ret < 0)
687d2a5f9aSShuming Fan goto read_error;
697d2a5f9aSShuming Fan ret = rt700_index_read(rt700->regmap, RT700_IRQ_FLAG_TABLE2, &val81);
707d2a5f9aSShuming Fan if (ret < 0)
717d2a5f9aSShuming Fan goto read_error;
727d2a5f9aSShuming Fan
737d2a5f9aSShuming Fan val80 &= 0x0381;
747d2a5f9aSShuming Fan val81 &= 0xff00;
757d2a5f9aSShuming Fan
767d2a5f9aSShuming Fan switch (val80) {
777d2a5f9aSShuming Fan case 0x0200:
787d2a5f9aSShuming Fan case 0x0100:
797d2a5f9aSShuming Fan case 0x0080:
807d2a5f9aSShuming Fan btn_type |= SND_JACK_BTN_0;
817d2a5f9aSShuming Fan break;
827d2a5f9aSShuming Fan case 0x0001:
837d2a5f9aSShuming Fan btn_type |= SND_JACK_BTN_3;
847d2a5f9aSShuming Fan break;
857d2a5f9aSShuming Fan }
867d2a5f9aSShuming Fan switch (val81) {
877d2a5f9aSShuming Fan case 0x8000:
887d2a5f9aSShuming Fan case 0x4000:
897d2a5f9aSShuming Fan case 0x2000:
907d2a5f9aSShuming Fan btn_type |= SND_JACK_BTN_1;
917d2a5f9aSShuming Fan break;
927d2a5f9aSShuming Fan case 0x1000:
937d2a5f9aSShuming Fan case 0x0800:
947d2a5f9aSShuming Fan case 0x0400:
957d2a5f9aSShuming Fan btn_type |= SND_JACK_BTN_2;
967d2a5f9aSShuming Fan break;
977d2a5f9aSShuming Fan case 0x0200:
987d2a5f9aSShuming Fan case 0x0100:
997d2a5f9aSShuming Fan btn_type |= SND_JACK_BTN_3;
1007d2a5f9aSShuming Fan break;
1017d2a5f9aSShuming Fan }
1027d2a5f9aSShuming Fan read_error:
1037d2a5f9aSShuming Fan return btn_type;
1047d2a5f9aSShuming Fan }
1057d2a5f9aSShuming Fan
rt700_headset_detect(struct rt700_priv * rt700)1067d2a5f9aSShuming Fan static int rt700_headset_detect(struct rt700_priv *rt700)
1077d2a5f9aSShuming Fan {
1087d2a5f9aSShuming Fan unsigned int buf, loop = 0;
1097d2a5f9aSShuming Fan int ret;
1107d2a5f9aSShuming Fan unsigned int jack_status = 0, reg;
1117d2a5f9aSShuming Fan
1127d2a5f9aSShuming Fan ret = rt700_index_read(rt700->regmap,
1137d2a5f9aSShuming Fan RT700_COMBO_JACK_AUTO_CTL2, &buf);
1147d2a5f9aSShuming Fan if (ret < 0)
1157d2a5f9aSShuming Fan goto io_error;
1167d2a5f9aSShuming Fan
1177d2a5f9aSShuming Fan while (loop < 500 &&
1187d2a5f9aSShuming Fan (buf & RT700_COMBOJACK_AUTO_DET_STATUS) == 0) {
1197d2a5f9aSShuming Fan loop++;
1207d2a5f9aSShuming Fan
1217d2a5f9aSShuming Fan usleep_range(9000, 10000);
1227d2a5f9aSShuming Fan ret = rt700_index_read(rt700->regmap,
1237d2a5f9aSShuming Fan RT700_COMBO_JACK_AUTO_CTL2, &buf);
1247d2a5f9aSShuming Fan if (ret < 0)
1257d2a5f9aSShuming Fan goto io_error;
1267d2a5f9aSShuming Fan
1277d2a5f9aSShuming Fan reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT;
1287d2a5f9aSShuming Fan ret = regmap_read(rt700->regmap, reg, &jack_status);
1297d2a5f9aSShuming Fan if ((jack_status & (1 << 31)) == 0)
1307d2a5f9aSShuming Fan goto remove_error;
1317d2a5f9aSShuming Fan }
1327d2a5f9aSShuming Fan
1337d2a5f9aSShuming Fan if (loop >= 500)
1347d2a5f9aSShuming Fan goto to_error;
1357d2a5f9aSShuming Fan
1367d2a5f9aSShuming Fan if (buf & RT700_COMBOJACK_AUTO_DET_TRS)
1377d2a5f9aSShuming Fan rt700->jack_type = SND_JACK_HEADPHONE;
1387d2a5f9aSShuming Fan else if ((buf & RT700_COMBOJACK_AUTO_DET_CTIA) ||
1397d2a5f9aSShuming Fan (buf & RT700_COMBOJACK_AUTO_DET_OMTP))
1407d2a5f9aSShuming Fan rt700->jack_type = SND_JACK_HEADSET;
1417d2a5f9aSShuming Fan
1427d2a5f9aSShuming Fan return 0;
1437d2a5f9aSShuming Fan
1447d2a5f9aSShuming Fan to_error:
1457d2a5f9aSShuming Fan ret = -ETIMEDOUT;
1467d2a5f9aSShuming Fan pr_err_ratelimited("Time-out error in %s\n", __func__);
1477d2a5f9aSShuming Fan return ret;
1487d2a5f9aSShuming Fan io_error:
1497d2a5f9aSShuming Fan pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
1507d2a5f9aSShuming Fan return ret;
1517d2a5f9aSShuming Fan remove_error:
1527d2a5f9aSShuming Fan pr_err_ratelimited("Jack removal in %s\n", __func__);
1537d2a5f9aSShuming Fan return -ENODEV;
1547d2a5f9aSShuming Fan }
1557d2a5f9aSShuming Fan
rt700_jack_detect_handler(struct work_struct * work)1567d2a5f9aSShuming Fan static void rt700_jack_detect_handler(struct work_struct *work)
1577d2a5f9aSShuming Fan {
1587d2a5f9aSShuming Fan struct rt700_priv *rt700 =
1597d2a5f9aSShuming Fan container_of(work, struct rt700_priv, jack_detect_work.work);
1607d2a5f9aSShuming Fan int btn_type = 0, ret;
1617d2a5f9aSShuming Fan unsigned int jack_status = 0, reg;
1627d2a5f9aSShuming Fan
1637d2a5f9aSShuming Fan if (!rt700->hs_jack)
1647d2a5f9aSShuming Fan return;
1657d2a5f9aSShuming Fan
1668ec35236SKuninori Morimoto if (!snd_soc_card_is_instantiated(rt700->component->card))
1677d2a5f9aSShuming Fan return;
1687d2a5f9aSShuming Fan
1697d2a5f9aSShuming Fan reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT;
1707d2a5f9aSShuming Fan ret = regmap_read(rt700->regmap, reg, &jack_status);
1717d2a5f9aSShuming Fan if (ret < 0)
1727d2a5f9aSShuming Fan goto io_error;
1737d2a5f9aSShuming Fan
1747d2a5f9aSShuming Fan /* pin attached */
1757d2a5f9aSShuming Fan if (jack_status & (1 << 31)) {
1767d2a5f9aSShuming Fan /* jack in */
1777d2a5f9aSShuming Fan if (rt700->jack_type == 0) {
1787d2a5f9aSShuming Fan ret = rt700_headset_detect(rt700);
1797d2a5f9aSShuming Fan if (ret < 0)
1807d2a5f9aSShuming Fan return;
1817d2a5f9aSShuming Fan if (rt700->jack_type == SND_JACK_HEADSET)
1827d2a5f9aSShuming Fan btn_type = rt700_button_detect(rt700);
1837d2a5f9aSShuming Fan } else if (rt700->jack_type == SND_JACK_HEADSET) {
1847d2a5f9aSShuming Fan /* jack is already in, report button event */
1857d2a5f9aSShuming Fan btn_type = rt700_button_detect(rt700);
1867d2a5f9aSShuming Fan }
1877d2a5f9aSShuming Fan } else {
1887d2a5f9aSShuming Fan /* jack out */
1897d2a5f9aSShuming Fan rt700->jack_type = 0;
1907d2a5f9aSShuming Fan }
1917d2a5f9aSShuming Fan
1927d2a5f9aSShuming Fan dev_dbg(&rt700->slave->dev,
1937d2a5f9aSShuming Fan "in %s, jack_type=0x%x\n", __func__, rt700->jack_type);
1947d2a5f9aSShuming Fan dev_dbg(&rt700->slave->dev,
1957d2a5f9aSShuming Fan "in %s, btn_type=0x%x\n", __func__, btn_type);
1967d2a5f9aSShuming Fan
1977d2a5f9aSShuming Fan snd_soc_jack_report(rt700->hs_jack, rt700->jack_type | btn_type,
1987d2a5f9aSShuming Fan SND_JACK_HEADSET |
1997d2a5f9aSShuming Fan SND_JACK_BTN_0 | SND_JACK_BTN_1 |
2007d2a5f9aSShuming Fan SND_JACK_BTN_2 | SND_JACK_BTN_3);
2017d2a5f9aSShuming Fan
2027d2a5f9aSShuming Fan if (btn_type) {
2037d2a5f9aSShuming Fan /* button released */
2047d2a5f9aSShuming Fan snd_soc_jack_report(rt700->hs_jack, rt700->jack_type,
2057d2a5f9aSShuming Fan SND_JACK_HEADSET |
2067d2a5f9aSShuming Fan SND_JACK_BTN_0 | SND_JACK_BTN_1 |
2077d2a5f9aSShuming Fan SND_JACK_BTN_2 | SND_JACK_BTN_3);
2087d2a5f9aSShuming Fan
2097d2a5f9aSShuming Fan mod_delayed_work(system_power_efficient_wq,
2107d2a5f9aSShuming Fan &rt700->jack_btn_check_work, msecs_to_jiffies(200));
2117d2a5f9aSShuming Fan }
2127d2a5f9aSShuming Fan
2137d2a5f9aSShuming Fan return;
2147d2a5f9aSShuming Fan
2157d2a5f9aSShuming Fan io_error:
2167d2a5f9aSShuming Fan pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
2177d2a5f9aSShuming Fan }
2187d2a5f9aSShuming Fan
rt700_btn_check_handler(struct work_struct * work)2197d2a5f9aSShuming Fan static void rt700_btn_check_handler(struct work_struct *work)
2207d2a5f9aSShuming Fan {
2217d2a5f9aSShuming Fan struct rt700_priv *rt700 = container_of(work, struct rt700_priv,
2227d2a5f9aSShuming Fan jack_btn_check_work.work);
2237d2a5f9aSShuming Fan int btn_type = 0, ret;
2247d2a5f9aSShuming Fan unsigned int jack_status = 0, reg;
2257d2a5f9aSShuming Fan
2267d2a5f9aSShuming Fan reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT;
2277d2a5f9aSShuming Fan ret = regmap_read(rt700->regmap, reg, &jack_status);
2287d2a5f9aSShuming Fan if (ret < 0)
2297d2a5f9aSShuming Fan goto io_error;
2307d2a5f9aSShuming Fan
2317d2a5f9aSShuming Fan /* pin attached */
2327d2a5f9aSShuming Fan if (jack_status & (1 << 31)) {
2337d2a5f9aSShuming Fan if (rt700->jack_type == SND_JACK_HEADSET) {
2347d2a5f9aSShuming Fan /* jack is already in, report button event */
2357d2a5f9aSShuming Fan btn_type = rt700_button_detect(rt700);
2367d2a5f9aSShuming Fan }
2377d2a5f9aSShuming Fan } else {
2387d2a5f9aSShuming Fan rt700->jack_type = 0;
2397d2a5f9aSShuming Fan }
2407d2a5f9aSShuming Fan
2417d2a5f9aSShuming Fan /* cbj comparator */
2427d2a5f9aSShuming Fan ret = rt700_index_read(rt700->regmap, RT700_COMBO_JACK_AUTO_CTL2, ®);
2437d2a5f9aSShuming Fan if (ret < 0)
2447d2a5f9aSShuming Fan goto io_error;
2457d2a5f9aSShuming Fan
2467d2a5f9aSShuming Fan if ((reg & 0xf0) == 0xf0)
2477d2a5f9aSShuming Fan btn_type = 0;
2487d2a5f9aSShuming Fan
2497d2a5f9aSShuming Fan dev_dbg(&rt700->slave->dev,
2507d2a5f9aSShuming Fan "%s, btn_type=0x%x\n", __func__, btn_type);
2517d2a5f9aSShuming Fan snd_soc_jack_report(rt700->hs_jack, rt700->jack_type | btn_type,
2527d2a5f9aSShuming Fan SND_JACK_HEADSET |
2537d2a5f9aSShuming Fan SND_JACK_BTN_0 | SND_JACK_BTN_1 |
2547d2a5f9aSShuming Fan SND_JACK_BTN_2 | SND_JACK_BTN_3);
2557d2a5f9aSShuming Fan
2567d2a5f9aSShuming Fan if (btn_type) {
2577d2a5f9aSShuming Fan /* button released */
2587d2a5f9aSShuming Fan snd_soc_jack_report(rt700->hs_jack, rt700->jack_type,
2597d2a5f9aSShuming Fan SND_JACK_HEADSET |
2607d2a5f9aSShuming Fan SND_JACK_BTN_0 | SND_JACK_BTN_1 |
2617d2a5f9aSShuming Fan SND_JACK_BTN_2 | SND_JACK_BTN_3);
2627d2a5f9aSShuming Fan
2637d2a5f9aSShuming Fan mod_delayed_work(system_power_efficient_wq,
2647d2a5f9aSShuming Fan &rt700->jack_btn_check_work, msecs_to_jiffies(200));
2657d2a5f9aSShuming Fan }
2667d2a5f9aSShuming Fan
2677d2a5f9aSShuming Fan return;
2687d2a5f9aSShuming Fan
2697d2a5f9aSShuming Fan io_error:
2707d2a5f9aSShuming Fan pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
2717d2a5f9aSShuming Fan }
2727d2a5f9aSShuming Fan
rt700_jack_init(struct rt700_priv * rt700)2737d2a5f9aSShuming Fan static void rt700_jack_init(struct rt700_priv *rt700)
2747d2a5f9aSShuming Fan {
2757d2a5f9aSShuming Fan struct snd_soc_dapm_context *dapm =
2767d2a5f9aSShuming Fan snd_soc_component_get_dapm(rt700->component);
2777d2a5f9aSShuming Fan
2787d2a5f9aSShuming Fan /* power on */
2797d2a5f9aSShuming Fan if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
2807d2a5f9aSShuming Fan regmap_write(rt700->regmap,
2817d2a5f9aSShuming Fan RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
2827d2a5f9aSShuming Fan
2837d2a5f9aSShuming Fan if (rt700->hs_jack) {
2847d2a5f9aSShuming Fan /* Enable Jack Detection */
2857d2a5f9aSShuming Fan regmap_write(rt700->regmap,
2867d2a5f9aSShuming Fan RT700_SET_MIC2_UNSOLICITED_ENABLE, 0x82);
2877d2a5f9aSShuming Fan regmap_write(rt700->regmap,
2887d2a5f9aSShuming Fan RT700_SET_HP_UNSOLICITED_ENABLE, 0x81);
2897d2a5f9aSShuming Fan regmap_write(rt700->regmap,
2907d2a5f9aSShuming Fan RT700_SET_INLINE_UNSOLICITED_ENABLE, 0x83);
2917d2a5f9aSShuming Fan rt700_index_write(rt700->regmap, 0x10, 0x2420);
2927d2a5f9aSShuming Fan rt700_index_write(rt700->regmap, 0x19, 0x2e11);
2937d2a5f9aSShuming Fan
2947d2a5f9aSShuming Fan dev_dbg(&rt700->slave->dev, "in %s enable\n", __func__);
2957d2a5f9aSShuming Fan
2967d2a5f9aSShuming Fan mod_delayed_work(system_power_efficient_wq,
2977d2a5f9aSShuming Fan &rt700->jack_detect_work, msecs_to_jiffies(250));
2987d2a5f9aSShuming Fan } else {
2997d2a5f9aSShuming Fan regmap_write(rt700->regmap,
3007d2a5f9aSShuming Fan RT700_SET_MIC2_UNSOLICITED_ENABLE, 0x00);
3017d2a5f9aSShuming Fan regmap_write(rt700->regmap,
3027d2a5f9aSShuming Fan RT700_SET_HP_UNSOLICITED_ENABLE, 0x00);
3037d2a5f9aSShuming Fan regmap_write(rt700->regmap,
3047d2a5f9aSShuming Fan RT700_SET_INLINE_UNSOLICITED_ENABLE, 0x00);
3057d2a5f9aSShuming Fan
3067d2a5f9aSShuming Fan dev_dbg(&rt700->slave->dev, "in %s disable\n", __func__);
3077d2a5f9aSShuming Fan }
3087d2a5f9aSShuming Fan
3097d2a5f9aSShuming Fan /* power off */
3107d2a5f9aSShuming Fan if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
3117d2a5f9aSShuming Fan regmap_write(rt700->regmap,
3127d2a5f9aSShuming Fan RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
3137d2a5f9aSShuming Fan }
3147d2a5f9aSShuming Fan
rt700_set_jack_detect(struct snd_soc_component * component,struct snd_soc_jack * hs_jack,void * data)3157d2a5f9aSShuming Fan static int rt700_set_jack_detect(struct snd_soc_component *component,
3167d2a5f9aSShuming Fan struct snd_soc_jack *hs_jack, void *data)
3177d2a5f9aSShuming Fan {
3187d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
319e02b99e9SPierre-Louis Bossart int ret;
3207d2a5f9aSShuming Fan
3217d2a5f9aSShuming Fan rt700->hs_jack = hs_jack;
3227d2a5f9aSShuming Fan
323*6b8f8c5eSPierre-Louis Bossart /* we can only resume if the device was initialized at least once */
324*6b8f8c5eSPierre-Louis Bossart if (!rt700->first_hw_init)
325*6b8f8c5eSPierre-Louis Bossart return 0;
326*6b8f8c5eSPierre-Louis Bossart
327e02b99e9SPierre-Louis Bossart ret = pm_runtime_resume_and_get(component->dev);
328e02b99e9SPierre-Louis Bossart if (ret < 0) {
329e02b99e9SPierre-Louis Bossart if (ret != -EACCES) {
330e02b99e9SPierre-Louis Bossart dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
331e02b99e9SPierre-Louis Bossart return ret;
332e02b99e9SPierre-Louis Bossart }
333e02b99e9SPierre-Louis Bossart
334e02b99e9SPierre-Louis Bossart /* pm_runtime not enabled yet */
335e02b99e9SPierre-Louis Bossart dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
3367d2a5f9aSShuming Fan return 0;
3377d2a5f9aSShuming Fan }
3387d2a5f9aSShuming Fan
3397d2a5f9aSShuming Fan rt700_jack_init(rt700);
3407d2a5f9aSShuming Fan
341e02b99e9SPierre-Louis Bossart pm_runtime_mark_last_busy(component->dev);
342e02b99e9SPierre-Louis Bossart pm_runtime_put_autosuspend(component->dev);
343e02b99e9SPierre-Louis Bossart
3447d2a5f9aSShuming Fan return 0;
3457d2a5f9aSShuming Fan }
3467d2a5f9aSShuming Fan
rt700_get_gain(struct rt700_priv * rt700,unsigned int addr_h,unsigned int addr_l,unsigned int val_h,unsigned int * r_val,unsigned int * l_val)3477d2a5f9aSShuming Fan static void rt700_get_gain(struct rt700_priv *rt700, unsigned int addr_h,
3487d2a5f9aSShuming Fan unsigned int addr_l, unsigned int val_h,
3497d2a5f9aSShuming Fan unsigned int *r_val, unsigned int *l_val)
3507d2a5f9aSShuming Fan {
3517d2a5f9aSShuming Fan /* R Channel */
3527d2a5f9aSShuming Fan *r_val = (val_h << 8);
3537d2a5f9aSShuming Fan regmap_read(rt700->regmap, addr_l, r_val);
3547d2a5f9aSShuming Fan
3557d2a5f9aSShuming Fan /* L Channel */
3567d2a5f9aSShuming Fan val_h |= 0x20;
3577d2a5f9aSShuming Fan *l_val = (val_h << 8);
3587d2a5f9aSShuming Fan regmap_read(rt700->regmap, addr_h, l_val);
3597d2a5f9aSShuming Fan }
3607d2a5f9aSShuming Fan
3617d2a5f9aSShuming Fan /* For Verb-Set Amplifier Gain (Verb ID = 3h) */
rt700_set_amp_gain_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3627d2a5f9aSShuming Fan static int rt700_set_amp_gain_put(struct snd_kcontrol *kcontrol,
3637d2a5f9aSShuming Fan struct snd_ctl_elem_value *ucontrol)
3647d2a5f9aSShuming Fan {
3657d2a5f9aSShuming Fan struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
3667d2a5f9aSShuming Fan struct snd_soc_dapm_context *dapm =
3677d2a5f9aSShuming Fan snd_soc_component_get_dapm(component);
3687d2a5f9aSShuming Fan struct soc_mixer_control *mc =
3697d2a5f9aSShuming Fan (struct soc_mixer_control *)kcontrol->private_value;
3707d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
3717d2a5f9aSShuming Fan unsigned int addr_h, addr_l, val_h, val_ll, val_lr;
3727d2a5f9aSShuming Fan unsigned int read_ll, read_rl;
3737d2a5f9aSShuming Fan int i;
3747d2a5f9aSShuming Fan
3757d2a5f9aSShuming Fan /* Can't use update bit function, so read the original value first */
3767d2a5f9aSShuming Fan addr_h = mc->reg;
3777d2a5f9aSShuming Fan addr_l = mc->rreg;
3787d2a5f9aSShuming Fan if (mc->shift == RT700_DIR_OUT_SFT) /* output */
3797d2a5f9aSShuming Fan val_h = 0x80;
3807d2a5f9aSShuming Fan else /* input */
3817d2a5f9aSShuming Fan val_h = 0x0;
3827d2a5f9aSShuming Fan
3837d2a5f9aSShuming Fan rt700_get_gain(rt700, addr_h, addr_l, val_h, &read_rl, &read_ll);
3847d2a5f9aSShuming Fan
3857d2a5f9aSShuming Fan /* L Channel */
3867d2a5f9aSShuming Fan if (mc->invert) {
3877d2a5f9aSShuming Fan /* for mute */
3887d2a5f9aSShuming Fan val_ll = (mc->max - ucontrol->value.integer.value[0]) << 7;
3897d2a5f9aSShuming Fan /* keep gain */
3907d2a5f9aSShuming Fan read_ll = read_ll & 0x7f;
3917d2a5f9aSShuming Fan val_ll |= read_ll;
3927d2a5f9aSShuming Fan } else {
3937d2a5f9aSShuming Fan /* for gain */
3947d2a5f9aSShuming Fan val_ll = ((ucontrol->value.integer.value[0]) & 0x7f);
3957d2a5f9aSShuming Fan if (val_ll > mc->max)
3967d2a5f9aSShuming Fan val_ll = mc->max;
3977d2a5f9aSShuming Fan /* keep mute status */
3987d2a5f9aSShuming Fan read_ll = read_ll & 0x80;
3997d2a5f9aSShuming Fan val_ll |= read_ll;
4007d2a5f9aSShuming Fan }
4017d2a5f9aSShuming Fan
4027d2a5f9aSShuming Fan if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
4037d2a5f9aSShuming Fan regmap_write(rt700->regmap,
4047d2a5f9aSShuming Fan RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
4057d2a5f9aSShuming Fan
4067d2a5f9aSShuming Fan /* R Channel */
4077d2a5f9aSShuming Fan if (mc->invert) {
4087d2a5f9aSShuming Fan /* for mute */
4097d2a5f9aSShuming Fan val_lr = (mc->max - ucontrol->value.integer.value[1]) << 7;
4107d2a5f9aSShuming Fan /* keep gain */
4117d2a5f9aSShuming Fan read_rl = read_rl & 0x7f;
4127d2a5f9aSShuming Fan val_lr |= read_rl;
4137d2a5f9aSShuming Fan } else {
4147d2a5f9aSShuming Fan /* for gain */
4157d2a5f9aSShuming Fan val_lr = ((ucontrol->value.integer.value[1]) & 0x7f);
4167d2a5f9aSShuming Fan if (val_lr > mc->max)
4177d2a5f9aSShuming Fan val_lr = mc->max;
4187d2a5f9aSShuming Fan /* keep mute status */
4197d2a5f9aSShuming Fan read_rl = read_rl & 0x80;
4207d2a5f9aSShuming Fan val_lr |= read_rl;
4217d2a5f9aSShuming Fan }
4227d2a5f9aSShuming Fan
4237d2a5f9aSShuming Fan for (i = 0; i < 3; i++) { /* retry 3 times at most */
4247d2a5f9aSShuming Fan if (val_ll == val_lr) {
4257d2a5f9aSShuming Fan /* Set both L/R channels at the same time */
4267d2a5f9aSShuming Fan val_h = (1 << mc->shift) | (3 << 4);
4277d2a5f9aSShuming Fan regmap_write(rt700->regmap,
4287d2a5f9aSShuming Fan addr_h, (val_h << 8 | val_ll));
4297d2a5f9aSShuming Fan regmap_write(rt700->regmap,
4307d2a5f9aSShuming Fan addr_l, (val_h << 8 | val_ll));
4317d2a5f9aSShuming Fan } else {
4327d2a5f9aSShuming Fan /* Lch*/
4337d2a5f9aSShuming Fan val_h = (1 << mc->shift) | (1 << 5);
4347d2a5f9aSShuming Fan regmap_write(rt700->regmap,
4357d2a5f9aSShuming Fan addr_h, (val_h << 8 | val_ll));
4367d2a5f9aSShuming Fan
4377d2a5f9aSShuming Fan /* Rch */
4387d2a5f9aSShuming Fan val_h = (1 << mc->shift) | (1 << 4);
4397d2a5f9aSShuming Fan regmap_write(rt700->regmap,
4407d2a5f9aSShuming Fan addr_l, (val_h << 8 | val_lr));
4417d2a5f9aSShuming Fan }
4427d2a5f9aSShuming Fan /* check result */
4437d2a5f9aSShuming Fan if (mc->shift == RT700_DIR_OUT_SFT) /* output */
4447d2a5f9aSShuming Fan val_h = 0x80;
4457d2a5f9aSShuming Fan else /* input */
4467d2a5f9aSShuming Fan val_h = 0x0;
4477d2a5f9aSShuming Fan
4487d2a5f9aSShuming Fan rt700_get_gain(rt700, addr_h, addr_l, val_h,
4497d2a5f9aSShuming Fan &read_rl, &read_ll);
4507d2a5f9aSShuming Fan if (read_rl == val_lr && read_ll == val_ll)
4517d2a5f9aSShuming Fan break;
4527d2a5f9aSShuming Fan }
4537d2a5f9aSShuming Fan
4547d2a5f9aSShuming Fan if (dapm->bias_level <= SND_SOC_BIAS_STANDBY)
4557d2a5f9aSShuming Fan regmap_write(rt700->regmap,
4567d2a5f9aSShuming Fan RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
4577d2a5f9aSShuming Fan return 0;
4587d2a5f9aSShuming Fan }
4597d2a5f9aSShuming Fan
rt700_set_amp_gain_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4607d2a5f9aSShuming Fan static int rt700_set_amp_gain_get(struct snd_kcontrol *kcontrol,
4617d2a5f9aSShuming Fan struct snd_ctl_elem_value *ucontrol)
4627d2a5f9aSShuming Fan {
4637d2a5f9aSShuming Fan struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
4647d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
4657d2a5f9aSShuming Fan struct soc_mixer_control *mc =
4667d2a5f9aSShuming Fan (struct soc_mixer_control *)kcontrol->private_value;
4677d2a5f9aSShuming Fan unsigned int addr_h, addr_l, val_h;
4687d2a5f9aSShuming Fan unsigned int read_ll, read_rl;
4697d2a5f9aSShuming Fan
4707d2a5f9aSShuming Fan addr_h = mc->reg;
4717d2a5f9aSShuming Fan addr_l = mc->rreg;
4727d2a5f9aSShuming Fan if (mc->shift == RT700_DIR_OUT_SFT) /* output */
4737d2a5f9aSShuming Fan val_h = 0x80;
4747d2a5f9aSShuming Fan else /* input */
4757d2a5f9aSShuming Fan val_h = 0x0;
4767d2a5f9aSShuming Fan
4777d2a5f9aSShuming Fan rt700_get_gain(rt700, addr_h, addr_l, val_h, &read_rl, &read_ll);
4787d2a5f9aSShuming Fan
4797d2a5f9aSShuming Fan if (mc->invert) {
4807d2a5f9aSShuming Fan /* for mute status */
4817d2a5f9aSShuming Fan read_ll = !((read_ll & 0x80) >> RT700_MUTE_SFT);
4827d2a5f9aSShuming Fan read_rl = !((read_rl & 0x80) >> RT700_MUTE_SFT);
4837d2a5f9aSShuming Fan } else {
4847d2a5f9aSShuming Fan /* for gain */
4857d2a5f9aSShuming Fan read_ll = read_ll & 0x7f;
4867d2a5f9aSShuming Fan read_rl = read_rl & 0x7f;
4877d2a5f9aSShuming Fan }
4887d2a5f9aSShuming Fan ucontrol->value.integer.value[0] = read_ll;
4897d2a5f9aSShuming Fan ucontrol->value.integer.value[1] = read_rl;
4907d2a5f9aSShuming Fan
4917d2a5f9aSShuming Fan return 0;
4927d2a5f9aSShuming Fan }
4937d2a5f9aSShuming Fan
4947d2a5f9aSShuming Fan static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
4957d2a5f9aSShuming Fan static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
4967d2a5f9aSShuming Fan static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
4977d2a5f9aSShuming Fan
4987d2a5f9aSShuming Fan static const struct snd_kcontrol_new rt700_snd_controls[] = {
4997d2a5f9aSShuming Fan SOC_DOUBLE_R_EXT_TLV("DAC Front Playback Volume",
5007d2a5f9aSShuming Fan RT700_SET_GAIN_DAC1_H, RT700_SET_GAIN_DAC1_L,
5017d2a5f9aSShuming Fan RT700_DIR_OUT_SFT, 0x57, 0,
5027d2a5f9aSShuming Fan rt700_set_amp_gain_get, rt700_set_amp_gain_put, out_vol_tlv),
5037d2a5f9aSShuming Fan SOC_DOUBLE_R_EXT("ADC 08 Capture Switch",
5047d2a5f9aSShuming Fan RT700_SET_GAIN_ADC2_H, RT700_SET_GAIN_ADC2_L,
5057d2a5f9aSShuming Fan RT700_DIR_IN_SFT, 1, 1,
5067d2a5f9aSShuming Fan rt700_set_amp_gain_get, rt700_set_amp_gain_put),
5077d2a5f9aSShuming Fan SOC_DOUBLE_R_EXT("ADC 09 Capture Switch",
5087d2a5f9aSShuming Fan RT700_SET_GAIN_ADC1_H, RT700_SET_GAIN_ADC1_L,
5097d2a5f9aSShuming Fan RT700_DIR_IN_SFT, 1, 1,
5107d2a5f9aSShuming Fan rt700_set_amp_gain_get, rt700_set_amp_gain_put),
5117d2a5f9aSShuming Fan SOC_DOUBLE_R_EXT_TLV("ADC 08 Capture Volume",
5127d2a5f9aSShuming Fan RT700_SET_GAIN_ADC2_H, RT700_SET_GAIN_ADC2_L,
5137d2a5f9aSShuming Fan RT700_DIR_IN_SFT, 0x3f, 0,
5147d2a5f9aSShuming Fan rt700_set_amp_gain_get, rt700_set_amp_gain_put, in_vol_tlv),
5157d2a5f9aSShuming Fan SOC_DOUBLE_R_EXT_TLV("ADC 09 Capture Volume",
5167d2a5f9aSShuming Fan RT700_SET_GAIN_ADC1_H, RT700_SET_GAIN_ADC1_L,
5177d2a5f9aSShuming Fan RT700_DIR_IN_SFT, 0x3f, 0,
5187d2a5f9aSShuming Fan rt700_set_amp_gain_get, rt700_set_amp_gain_put, in_vol_tlv),
5197d2a5f9aSShuming Fan SOC_DOUBLE_R_EXT_TLV("AMIC Volume",
5207d2a5f9aSShuming Fan RT700_SET_GAIN_AMIC_H, RT700_SET_GAIN_AMIC_L,
5217d2a5f9aSShuming Fan RT700_DIR_IN_SFT, 3, 0,
5227d2a5f9aSShuming Fan rt700_set_amp_gain_get, rt700_set_amp_gain_put, mic_vol_tlv),
5237d2a5f9aSShuming Fan };
5247d2a5f9aSShuming Fan
rt700_mux_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5257d2a5f9aSShuming Fan static int rt700_mux_get(struct snd_kcontrol *kcontrol,
5267d2a5f9aSShuming Fan struct snd_ctl_elem_value *ucontrol)
5277d2a5f9aSShuming Fan {
5287d2a5f9aSShuming Fan struct snd_soc_component *component =
5297d2a5f9aSShuming Fan snd_soc_dapm_kcontrol_component(kcontrol);
5307d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
5317d2a5f9aSShuming Fan unsigned int reg, val = 0, nid;
5327d2a5f9aSShuming Fan int ret;
5337d2a5f9aSShuming Fan
5347d2a5f9aSShuming Fan if (strstr(ucontrol->id.name, "HPO Mux"))
5357d2a5f9aSShuming Fan nid = RT700_HP_OUT;
5367d2a5f9aSShuming Fan else if (strstr(ucontrol->id.name, "ADC 22 Mux"))
5377d2a5f9aSShuming Fan nid = RT700_MIXER_IN1;
5387d2a5f9aSShuming Fan else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
5397d2a5f9aSShuming Fan nid = RT700_MIXER_IN2;
5407d2a5f9aSShuming Fan else
5417d2a5f9aSShuming Fan return -EINVAL;
5427d2a5f9aSShuming Fan
5437d2a5f9aSShuming Fan /* vid = 0xf01 */
5447d2a5f9aSShuming Fan reg = RT700_VERB_SET_CONNECT_SEL | nid;
5457d2a5f9aSShuming Fan ret = regmap_read(rt700->regmap, reg, &val);
5467d2a5f9aSShuming Fan if (ret < 0)
5477d2a5f9aSShuming Fan return ret;
5487d2a5f9aSShuming Fan
5497d2a5f9aSShuming Fan ucontrol->value.enumerated.item[0] = val;
5507d2a5f9aSShuming Fan
5517d2a5f9aSShuming Fan return 0;
5527d2a5f9aSShuming Fan }
5537d2a5f9aSShuming Fan
rt700_mux_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5547d2a5f9aSShuming Fan static int rt700_mux_put(struct snd_kcontrol *kcontrol,
5557d2a5f9aSShuming Fan struct snd_ctl_elem_value *ucontrol)
5567d2a5f9aSShuming Fan {
5577d2a5f9aSShuming Fan struct snd_soc_component *component =
5587d2a5f9aSShuming Fan snd_soc_dapm_kcontrol_component(kcontrol);
5597d2a5f9aSShuming Fan struct snd_soc_dapm_context *dapm =
5607d2a5f9aSShuming Fan snd_soc_dapm_kcontrol_dapm(kcontrol);
5617d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
5627d2a5f9aSShuming Fan struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
5637d2a5f9aSShuming Fan unsigned int *item = ucontrol->value.enumerated.item;
5647d2a5f9aSShuming Fan unsigned int val, val2 = 0, change, reg, nid;
5657d2a5f9aSShuming Fan int ret;
5667d2a5f9aSShuming Fan
5677d2a5f9aSShuming Fan if (item[0] >= e->items)
5687d2a5f9aSShuming Fan return -EINVAL;
5697d2a5f9aSShuming Fan
5707d2a5f9aSShuming Fan if (strstr(ucontrol->id.name, "HPO Mux"))
5717d2a5f9aSShuming Fan nid = RT700_HP_OUT;
5727d2a5f9aSShuming Fan else if (strstr(ucontrol->id.name, "ADC 22 Mux"))
5737d2a5f9aSShuming Fan nid = RT700_MIXER_IN1;
5747d2a5f9aSShuming Fan else if (strstr(ucontrol->id.name, "ADC 23 Mux"))
5757d2a5f9aSShuming Fan nid = RT700_MIXER_IN2;
5767d2a5f9aSShuming Fan else
5777d2a5f9aSShuming Fan return -EINVAL;
5787d2a5f9aSShuming Fan
5797d2a5f9aSShuming Fan /* Verb ID = 0x701h */
5807d2a5f9aSShuming Fan val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
5817d2a5f9aSShuming Fan
5827d2a5f9aSShuming Fan reg = RT700_VERB_SET_CONNECT_SEL | nid;
5837d2a5f9aSShuming Fan ret = regmap_read(rt700->regmap, reg, &val2);
5847d2a5f9aSShuming Fan if (ret < 0)
5857d2a5f9aSShuming Fan return ret;
5867d2a5f9aSShuming Fan
5877d2a5f9aSShuming Fan if (val == val2)
5887d2a5f9aSShuming Fan change = 0;
5897d2a5f9aSShuming Fan else
5907d2a5f9aSShuming Fan change = 1;
5917d2a5f9aSShuming Fan
5927d2a5f9aSShuming Fan if (change) {
5937d2a5f9aSShuming Fan reg = RT700_VERB_SET_CONNECT_SEL | nid;
5947d2a5f9aSShuming Fan regmap_write(rt700->regmap, reg, val);
5957d2a5f9aSShuming Fan }
5967d2a5f9aSShuming Fan
5977d2a5f9aSShuming Fan snd_soc_dapm_mux_update_power(dapm, kcontrol,
5987d2a5f9aSShuming Fan item[0], e, NULL);
5997d2a5f9aSShuming Fan
6007d2a5f9aSShuming Fan return change;
6017d2a5f9aSShuming Fan }
6027d2a5f9aSShuming Fan
6037d2a5f9aSShuming Fan static const char * const adc_mux_text[] = {
6047d2a5f9aSShuming Fan "MIC2",
6057d2a5f9aSShuming Fan "LINE1",
6067d2a5f9aSShuming Fan "LINE2",
6077d2a5f9aSShuming Fan "DMIC",
6087d2a5f9aSShuming Fan };
6097d2a5f9aSShuming Fan
6107d2a5f9aSShuming Fan static SOC_ENUM_SINGLE_DECL(
6117d2a5f9aSShuming Fan rt700_adc22_enum, SND_SOC_NOPM, 0, adc_mux_text);
6127d2a5f9aSShuming Fan
6137d2a5f9aSShuming Fan static SOC_ENUM_SINGLE_DECL(
6147d2a5f9aSShuming Fan rt700_adc23_enum, SND_SOC_NOPM, 0, adc_mux_text);
6157d2a5f9aSShuming Fan
6167d2a5f9aSShuming Fan static const struct snd_kcontrol_new rt700_adc22_mux =
6177d2a5f9aSShuming Fan SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt700_adc22_enum,
6187d2a5f9aSShuming Fan rt700_mux_get, rt700_mux_put);
6197d2a5f9aSShuming Fan
6207d2a5f9aSShuming Fan static const struct snd_kcontrol_new rt700_adc23_mux =
6217d2a5f9aSShuming Fan SOC_DAPM_ENUM_EXT("ADC 23 Mux", rt700_adc23_enum,
6227d2a5f9aSShuming Fan rt700_mux_get, rt700_mux_put);
6237d2a5f9aSShuming Fan
6247d2a5f9aSShuming Fan static const char * const out_mux_text[] = {
6257d2a5f9aSShuming Fan "Front",
6267d2a5f9aSShuming Fan "Surround",
6277d2a5f9aSShuming Fan };
6287d2a5f9aSShuming Fan
6297d2a5f9aSShuming Fan static SOC_ENUM_SINGLE_DECL(
6307d2a5f9aSShuming Fan rt700_hp_enum, SND_SOC_NOPM, 0, out_mux_text);
6317d2a5f9aSShuming Fan
6327d2a5f9aSShuming Fan static const struct snd_kcontrol_new rt700_hp_mux =
6337d2a5f9aSShuming Fan SOC_DAPM_ENUM_EXT("HP Mux", rt700_hp_enum,
6347d2a5f9aSShuming Fan rt700_mux_get, rt700_mux_put);
6357d2a5f9aSShuming Fan
rt700_dac_front_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)6367d2a5f9aSShuming Fan static int rt700_dac_front_event(struct snd_soc_dapm_widget *w,
6377d2a5f9aSShuming Fan struct snd_kcontrol *kcontrol, int event)
6387d2a5f9aSShuming Fan {
6397d2a5f9aSShuming Fan struct snd_soc_component *component =
6407d2a5f9aSShuming Fan snd_soc_dapm_to_component(w->dapm);
6417d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
6427d2a5f9aSShuming Fan
6437d2a5f9aSShuming Fan switch (event) {
6447d2a5f9aSShuming Fan case SND_SOC_DAPM_POST_PMU:
6457d2a5f9aSShuming Fan regmap_write(rt700->regmap,
6467d2a5f9aSShuming Fan RT700_SET_STREAMID_DAC1, 0x10);
6477d2a5f9aSShuming Fan break;
6487d2a5f9aSShuming Fan case SND_SOC_DAPM_PRE_PMD:
6497d2a5f9aSShuming Fan regmap_write(rt700->regmap,
6507d2a5f9aSShuming Fan RT700_SET_STREAMID_DAC1, 0x00);
6517d2a5f9aSShuming Fan break;
6527d2a5f9aSShuming Fan }
6537d2a5f9aSShuming Fan return 0;
6547d2a5f9aSShuming Fan }
6557d2a5f9aSShuming Fan
rt700_dac_surround_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)6567d2a5f9aSShuming Fan static int rt700_dac_surround_event(struct snd_soc_dapm_widget *w,
6577d2a5f9aSShuming Fan struct snd_kcontrol *kcontrol, int event)
6587d2a5f9aSShuming Fan {
6597d2a5f9aSShuming Fan struct snd_soc_component *component =
6607d2a5f9aSShuming Fan snd_soc_dapm_to_component(w->dapm);
6617d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
6627d2a5f9aSShuming Fan
6637d2a5f9aSShuming Fan switch (event) {
6647d2a5f9aSShuming Fan case SND_SOC_DAPM_POST_PMU:
6657d2a5f9aSShuming Fan regmap_write(rt700->regmap,
6667d2a5f9aSShuming Fan RT700_SET_STREAMID_DAC2, 0x10);
6677d2a5f9aSShuming Fan break;
6687d2a5f9aSShuming Fan case SND_SOC_DAPM_PRE_PMD:
6697d2a5f9aSShuming Fan regmap_write(rt700->regmap,
6707d2a5f9aSShuming Fan RT700_SET_STREAMID_DAC2, 0x00);
6717d2a5f9aSShuming Fan break;
6727d2a5f9aSShuming Fan }
6737d2a5f9aSShuming Fan return 0;
6747d2a5f9aSShuming Fan }
6757d2a5f9aSShuming Fan
rt700_adc_09_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)6767d2a5f9aSShuming Fan static int rt700_adc_09_event(struct snd_soc_dapm_widget *w,
6777d2a5f9aSShuming Fan struct snd_kcontrol *kcontrol, int event)
6787d2a5f9aSShuming Fan {
6797d2a5f9aSShuming Fan struct snd_soc_component *component =
6807d2a5f9aSShuming Fan snd_soc_dapm_to_component(w->dapm);
6817d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
6827d2a5f9aSShuming Fan
6837d2a5f9aSShuming Fan switch (event) {
6847d2a5f9aSShuming Fan case SND_SOC_DAPM_POST_PMU:
6857d2a5f9aSShuming Fan regmap_write(rt700->regmap,
6867d2a5f9aSShuming Fan RT700_SET_STREAMID_ADC1, 0x10);
6877d2a5f9aSShuming Fan break;
6887d2a5f9aSShuming Fan case SND_SOC_DAPM_PRE_PMD:
6897d2a5f9aSShuming Fan regmap_write(rt700->regmap,
6907d2a5f9aSShuming Fan RT700_SET_STREAMID_ADC1, 0x00);
6917d2a5f9aSShuming Fan break;
6927d2a5f9aSShuming Fan }
6937d2a5f9aSShuming Fan return 0;
6947d2a5f9aSShuming Fan }
6957d2a5f9aSShuming Fan
rt700_adc_08_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)6967d2a5f9aSShuming Fan static int rt700_adc_08_event(struct snd_soc_dapm_widget *w,
6977d2a5f9aSShuming Fan struct snd_kcontrol *kcontrol, int event)
6987d2a5f9aSShuming Fan {
6997d2a5f9aSShuming Fan struct snd_soc_component *component =
7007d2a5f9aSShuming Fan snd_soc_dapm_to_component(w->dapm);
7017d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
7027d2a5f9aSShuming Fan
7037d2a5f9aSShuming Fan switch (event) {
7047d2a5f9aSShuming Fan case SND_SOC_DAPM_POST_PMU:
7057d2a5f9aSShuming Fan regmap_write(rt700->regmap,
7067d2a5f9aSShuming Fan RT700_SET_STREAMID_ADC2, 0x10);
7077d2a5f9aSShuming Fan break;
7087d2a5f9aSShuming Fan case SND_SOC_DAPM_PRE_PMD:
7097d2a5f9aSShuming Fan regmap_write(rt700->regmap,
7107d2a5f9aSShuming Fan RT700_SET_STREAMID_ADC2, 0x00);
7117d2a5f9aSShuming Fan break;
7127d2a5f9aSShuming Fan }
7137d2a5f9aSShuming Fan return 0;
7147d2a5f9aSShuming Fan }
7157d2a5f9aSShuming Fan
rt700_hpo_mux_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)7167d2a5f9aSShuming Fan static int rt700_hpo_mux_event(struct snd_soc_dapm_widget *w,
7177d2a5f9aSShuming Fan struct snd_kcontrol *kcontrol, int event)
7187d2a5f9aSShuming Fan {
7197d2a5f9aSShuming Fan struct snd_soc_component *component =
7207d2a5f9aSShuming Fan snd_soc_dapm_to_component(w->dapm);
7217d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
7227d2a5f9aSShuming Fan unsigned int val_h = (1 << RT700_DIR_OUT_SFT) | (0x3 << 4);
7237d2a5f9aSShuming Fan unsigned int val_l;
7247d2a5f9aSShuming Fan
7257d2a5f9aSShuming Fan switch (event) {
7267d2a5f9aSShuming Fan case SND_SOC_DAPM_POST_PMU:
7277d2a5f9aSShuming Fan val_l = 0x00;
7287d2a5f9aSShuming Fan regmap_write(rt700->regmap,
7297d2a5f9aSShuming Fan RT700_SET_GAIN_HP_H, (val_h << 8 | val_l));
7307d2a5f9aSShuming Fan break;
7317d2a5f9aSShuming Fan case SND_SOC_DAPM_PRE_PMD:
7327d2a5f9aSShuming Fan val_l = (1 << RT700_MUTE_SFT);
7337d2a5f9aSShuming Fan regmap_write(rt700->regmap,
7347d2a5f9aSShuming Fan RT700_SET_GAIN_HP_H, (val_h << 8 | val_l));
7357d2a5f9aSShuming Fan usleep_range(50000, 55000);
7367d2a5f9aSShuming Fan break;
7377d2a5f9aSShuming Fan }
7387d2a5f9aSShuming Fan return 0;
7397d2a5f9aSShuming Fan }
7407d2a5f9aSShuming Fan
rt700_spk_pga_event(struct snd_soc_dapm_widget * w,struct snd_kcontrol * kcontrol,int event)7417d2a5f9aSShuming Fan static int rt700_spk_pga_event(struct snd_soc_dapm_widget *w,
7427d2a5f9aSShuming Fan struct snd_kcontrol *kcontrol, int event)
7437d2a5f9aSShuming Fan {
7447d2a5f9aSShuming Fan struct snd_soc_component *component =
7457d2a5f9aSShuming Fan snd_soc_dapm_to_component(w->dapm);
7467d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
7477d2a5f9aSShuming Fan unsigned int val_h = (1 << RT700_DIR_OUT_SFT) | (0x3 << 4);
7487d2a5f9aSShuming Fan unsigned int val_l;
7497d2a5f9aSShuming Fan
7507d2a5f9aSShuming Fan switch (event) {
7517d2a5f9aSShuming Fan case SND_SOC_DAPM_POST_PMU:
7527d2a5f9aSShuming Fan val_l = 0x00;
7537d2a5f9aSShuming Fan regmap_write(rt700->regmap,
7547d2a5f9aSShuming Fan RT700_SET_GAIN_SPK_H, (val_h << 8 | val_l));
7557d2a5f9aSShuming Fan break;
7567d2a5f9aSShuming Fan case SND_SOC_DAPM_PRE_PMD:
7577d2a5f9aSShuming Fan val_l = (1 << RT700_MUTE_SFT);
7587d2a5f9aSShuming Fan regmap_write(rt700->regmap,
7597d2a5f9aSShuming Fan RT700_SET_GAIN_SPK_H, (val_h << 8 | val_l));
7607d2a5f9aSShuming Fan break;
7617d2a5f9aSShuming Fan }
7627d2a5f9aSShuming Fan return 0;
7637d2a5f9aSShuming Fan }
7647d2a5f9aSShuming Fan
7657d2a5f9aSShuming Fan static const struct snd_soc_dapm_widget rt700_dapm_widgets[] = {
7667d2a5f9aSShuming Fan SND_SOC_DAPM_OUTPUT("HP"),
7677d2a5f9aSShuming Fan SND_SOC_DAPM_OUTPUT("SPK"),
7687d2a5f9aSShuming Fan SND_SOC_DAPM_INPUT("DMIC1"),
7697d2a5f9aSShuming Fan SND_SOC_DAPM_INPUT("DMIC2"),
7707d2a5f9aSShuming Fan SND_SOC_DAPM_INPUT("MIC2"),
7717d2a5f9aSShuming Fan SND_SOC_DAPM_INPUT("LINE1"),
7727d2a5f9aSShuming Fan SND_SOC_DAPM_INPUT("LINE2"),
7737d2a5f9aSShuming Fan SND_SOC_DAPM_DAC_E("DAC Front", NULL, SND_SOC_NOPM, 0, 0,
7747d2a5f9aSShuming Fan rt700_dac_front_event,
7757d2a5f9aSShuming Fan SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
7767d2a5f9aSShuming Fan SND_SOC_DAPM_DAC_E("DAC Surround", NULL, SND_SOC_NOPM, 0, 0,
7777d2a5f9aSShuming Fan rt700_dac_surround_event,
7787d2a5f9aSShuming Fan SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
7797d2a5f9aSShuming Fan SND_SOC_DAPM_MUX_E("HPO Mux", SND_SOC_NOPM, 0, 0, &rt700_hp_mux,
7807d2a5f9aSShuming Fan rt700_hpo_mux_event,
7817d2a5f9aSShuming Fan SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
7827d2a5f9aSShuming Fan SND_SOC_DAPM_PGA_E("SPK PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
7837d2a5f9aSShuming Fan rt700_spk_pga_event,
7847d2a5f9aSShuming Fan SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
7857d2a5f9aSShuming Fan SND_SOC_DAPM_ADC_E("ADC 09", NULL, SND_SOC_NOPM, 0, 0,
7867d2a5f9aSShuming Fan rt700_adc_09_event,
7877d2a5f9aSShuming Fan SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
7887d2a5f9aSShuming Fan SND_SOC_DAPM_ADC_E("ADC 08", NULL, SND_SOC_NOPM, 0, 0,
7897d2a5f9aSShuming Fan rt700_adc_08_event,
7907d2a5f9aSShuming Fan SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
7917d2a5f9aSShuming Fan SND_SOC_DAPM_MUX("ADC 22 Mux", SND_SOC_NOPM, 0, 0,
7927d2a5f9aSShuming Fan &rt700_adc22_mux),
7937d2a5f9aSShuming Fan SND_SOC_DAPM_MUX("ADC 23 Mux", SND_SOC_NOPM, 0, 0,
7947d2a5f9aSShuming Fan &rt700_adc23_mux),
7957d2a5f9aSShuming Fan SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
7967d2a5f9aSShuming Fan SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
7977d2a5f9aSShuming Fan SND_SOC_DAPM_AIF_OUT("DP2TX", "DP2 Capture", 0, SND_SOC_NOPM, 0, 0),
7987d2a5f9aSShuming Fan SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
7997d2a5f9aSShuming Fan };
8007d2a5f9aSShuming Fan
8017d2a5f9aSShuming Fan static const struct snd_soc_dapm_route rt700_audio_map[] = {
8027d2a5f9aSShuming Fan {"DAC Front", NULL, "DP1RX"},
8037d2a5f9aSShuming Fan {"DAC Surround", NULL, "DP3RX"},
8047d2a5f9aSShuming Fan {"DP2TX", NULL, "ADC 09"},
8057d2a5f9aSShuming Fan {"DP4TX", NULL, "ADC 08"},
8067d2a5f9aSShuming Fan {"ADC 09", NULL, "ADC 22 Mux"},
8077d2a5f9aSShuming Fan {"ADC 08", NULL, "ADC 23 Mux"},
8087d2a5f9aSShuming Fan {"ADC 22 Mux", "DMIC", "DMIC1"},
8097d2a5f9aSShuming Fan {"ADC 22 Mux", "LINE1", "LINE1"},
8107d2a5f9aSShuming Fan {"ADC 22 Mux", "LINE2", "LINE2"},
8117d2a5f9aSShuming Fan {"ADC 22 Mux", "MIC2", "MIC2"},
8127d2a5f9aSShuming Fan {"ADC 23 Mux", "DMIC", "DMIC2"},
8137d2a5f9aSShuming Fan {"ADC 23 Mux", "LINE1", "LINE1"},
8147d2a5f9aSShuming Fan {"ADC 23 Mux", "LINE2", "LINE2"},
8157d2a5f9aSShuming Fan {"ADC 23 Mux", "MIC2", "MIC2"},
8167d2a5f9aSShuming Fan {"HPO Mux", "Front", "DAC Front"},
8177d2a5f9aSShuming Fan {"HPO Mux", "Surround", "DAC Surround"},
8187d2a5f9aSShuming Fan {"HP", NULL, "HPO Mux"},
8197d2a5f9aSShuming Fan {"SPK PGA", NULL, "DAC Front"},
8207d2a5f9aSShuming Fan {"SPK", NULL, "SPK PGA"},
8217d2a5f9aSShuming Fan };
8227d2a5f9aSShuming Fan
rt700_probe(struct snd_soc_component * component)8237d2a5f9aSShuming Fan static int rt700_probe(struct snd_soc_component *component)
8247d2a5f9aSShuming Fan {
8257d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
826011e397fSPierre-Louis Bossart int ret;
8277d2a5f9aSShuming Fan
8287d2a5f9aSShuming Fan rt700->component = component;
8297d2a5f9aSShuming Fan
830*6b8f8c5eSPierre-Louis Bossart if (!rt700->first_hw_init)
831*6b8f8c5eSPierre-Louis Bossart return 0;
832*6b8f8c5eSPierre-Louis Bossart
833011e397fSPierre-Louis Bossart ret = pm_runtime_resume(component->dev);
834011e397fSPierre-Louis Bossart if (ret < 0 && ret != -EACCES)
835011e397fSPierre-Louis Bossart return ret;
836011e397fSPierre-Louis Bossart
8377d2a5f9aSShuming Fan return 0;
8387d2a5f9aSShuming Fan }
8397d2a5f9aSShuming Fan
rt700_set_bias_level(struct snd_soc_component * component,enum snd_soc_bias_level level)8407d2a5f9aSShuming Fan static int rt700_set_bias_level(struct snd_soc_component *component,
8417d2a5f9aSShuming Fan enum snd_soc_bias_level level)
8427d2a5f9aSShuming Fan {
8437d2a5f9aSShuming Fan struct snd_soc_dapm_context *dapm =
8447d2a5f9aSShuming Fan snd_soc_component_get_dapm(component);
8457d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
8467d2a5f9aSShuming Fan
8477d2a5f9aSShuming Fan switch (level) {
8487d2a5f9aSShuming Fan case SND_SOC_BIAS_PREPARE:
8497d2a5f9aSShuming Fan if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
8507d2a5f9aSShuming Fan regmap_write(rt700->regmap,
8517d2a5f9aSShuming Fan RT700_SET_AUDIO_POWER_STATE,
8527d2a5f9aSShuming Fan AC_PWRST_D0);
8537d2a5f9aSShuming Fan }
8547d2a5f9aSShuming Fan break;
8557d2a5f9aSShuming Fan
8567d2a5f9aSShuming Fan case SND_SOC_BIAS_STANDBY:
8577d2a5f9aSShuming Fan regmap_write(rt700->regmap,
8587d2a5f9aSShuming Fan RT700_SET_AUDIO_POWER_STATE,
8597d2a5f9aSShuming Fan AC_PWRST_D3);
8607d2a5f9aSShuming Fan break;
8617d2a5f9aSShuming Fan
8627d2a5f9aSShuming Fan default:
8637d2a5f9aSShuming Fan break;
8647d2a5f9aSShuming Fan }
8657d2a5f9aSShuming Fan dapm->bias_level = level;
8667d2a5f9aSShuming Fan return 0;
8677d2a5f9aSShuming Fan }
8687d2a5f9aSShuming Fan
8697d2a5f9aSShuming Fan static const struct snd_soc_component_driver soc_codec_dev_rt700 = {
8707d2a5f9aSShuming Fan .probe = rt700_probe,
8717d2a5f9aSShuming Fan .set_bias_level = rt700_set_bias_level,
8727d2a5f9aSShuming Fan .controls = rt700_snd_controls,
8737d2a5f9aSShuming Fan .num_controls = ARRAY_SIZE(rt700_snd_controls),
8747d2a5f9aSShuming Fan .dapm_widgets = rt700_dapm_widgets,
8757d2a5f9aSShuming Fan .num_dapm_widgets = ARRAY_SIZE(rt700_dapm_widgets),
8767d2a5f9aSShuming Fan .dapm_routes = rt700_audio_map,
8777d2a5f9aSShuming Fan .num_dapm_routes = ARRAY_SIZE(rt700_audio_map),
8787d2a5f9aSShuming Fan .set_jack = rt700_set_jack_detect,
8794982fc1dSCharles Keepax .endianness = 1,
8807d2a5f9aSShuming Fan };
8817d2a5f9aSShuming Fan
rt700_set_sdw_stream(struct snd_soc_dai * dai,void * sdw_stream,int direction)8827d2a5f9aSShuming Fan static int rt700_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
8837d2a5f9aSShuming Fan int direction)
8847d2a5f9aSShuming Fan {
8853bcced01SPierre-Louis Bossart snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
8867d2a5f9aSShuming Fan
8877d2a5f9aSShuming Fan return 0;
8887d2a5f9aSShuming Fan }
8897d2a5f9aSShuming Fan
rt700_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)8907d2a5f9aSShuming Fan static void rt700_shutdown(struct snd_pcm_substream *substream,
8917d2a5f9aSShuming Fan struct snd_soc_dai *dai)
8927d2a5f9aSShuming Fan {
8937d2a5f9aSShuming Fan snd_soc_dai_set_dma_data(dai, substream, NULL);
8947d2a5f9aSShuming Fan }
8957d2a5f9aSShuming Fan
rt700_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)8967d2a5f9aSShuming Fan static int rt700_pcm_hw_params(struct snd_pcm_substream *substream,
8977d2a5f9aSShuming Fan struct snd_pcm_hw_params *params,
8987d2a5f9aSShuming Fan struct snd_soc_dai *dai)
8997d2a5f9aSShuming Fan {
9007d2a5f9aSShuming Fan struct snd_soc_component *component = dai->component;
9017d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
902ae7ad90eSCharles Keepax struct sdw_stream_config stream_config = {0};
903ae7ad90eSCharles Keepax struct sdw_port_config port_config = {0};
9043bcced01SPierre-Louis Bossart struct sdw_stream_runtime *sdw_stream;
905ae7ad90eSCharles Keepax int retval;
9067d2a5f9aSShuming Fan unsigned int val = 0;
9077d2a5f9aSShuming Fan
9087d2a5f9aSShuming Fan dev_dbg(dai->dev, "%s %s", __func__, dai->name);
9093bcced01SPierre-Louis Bossart sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
9107d2a5f9aSShuming Fan
9113bcced01SPierre-Louis Bossart if (!sdw_stream)
9127d2a5f9aSShuming Fan return -EINVAL;
9137d2a5f9aSShuming Fan
9147d2a5f9aSShuming Fan if (!rt700->slave)
9157d2a5f9aSShuming Fan return -EINVAL;
9167d2a5f9aSShuming Fan
9177d2a5f9aSShuming Fan /* SoundWire specific configuration */
918ae7ad90eSCharles Keepax snd_sdw_params_to_config(substream, params, &stream_config, &port_config);
919ae7ad90eSCharles Keepax
9207d2a5f9aSShuming Fan /* This code assumes port 1 for playback and port 2 for capture */
921ae7ad90eSCharles Keepax if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
922ae7ad90eSCharles Keepax port_config.num = 1;
923ae7ad90eSCharles Keepax else
924ae7ad90eSCharles Keepax port_config.num = 2;
9257d2a5f9aSShuming Fan
9267d2a5f9aSShuming Fan switch (dai->id) {
9277d2a5f9aSShuming Fan case RT700_AIF1:
9287d2a5f9aSShuming Fan break;
9297d2a5f9aSShuming Fan case RT700_AIF2:
930ae7ad90eSCharles Keepax port_config.num += 2;
9317d2a5f9aSShuming Fan break;
9327d2a5f9aSShuming Fan default:
9337d2a5f9aSShuming Fan dev_err(component->dev, "Invalid DAI id %d\n", dai->id);
9347d2a5f9aSShuming Fan return -EINVAL;
9357d2a5f9aSShuming Fan }
9367d2a5f9aSShuming Fan
9377d2a5f9aSShuming Fan retval = sdw_stream_add_slave(rt700->slave, &stream_config,
9383bcced01SPierre-Louis Bossart &port_config, 1, sdw_stream);
9397d2a5f9aSShuming Fan if (retval) {
9407d2a5f9aSShuming Fan dev_err(dai->dev, "Unable to configure port\n");
9417d2a5f9aSShuming Fan return retval;
9427d2a5f9aSShuming Fan }
9437d2a5f9aSShuming Fan
9447d2a5f9aSShuming Fan if (params_channels(params) <= 16) {
9457d2a5f9aSShuming Fan /* bit 3:0 Number of Channel */
9467d2a5f9aSShuming Fan val |= (params_channels(params) - 1);
9477d2a5f9aSShuming Fan } else {
9487d2a5f9aSShuming Fan dev_err(component->dev, "Unsupported channels %d\n",
9497d2a5f9aSShuming Fan params_channels(params));
9507d2a5f9aSShuming Fan return -EINVAL;
9517d2a5f9aSShuming Fan }
9527d2a5f9aSShuming Fan
9537d2a5f9aSShuming Fan switch (params_width(params)) {
9547d2a5f9aSShuming Fan /* bit 6:4 Bits per Sample */
9557d2a5f9aSShuming Fan case 8:
9567d2a5f9aSShuming Fan break;
9577d2a5f9aSShuming Fan case 16:
9587d2a5f9aSShuming Fan val |= (0x1 << 4);
9597d2a5f9aSShuming Fan break;
9607d2a5f9aSShuming Fan case 20:
9617d2a5f9aSShuming Fan val |= (0x2 << 4);
9627d2a5f9aSShuming Fan break;
9637d2a5f9aSShuming Fan case 24:
9647d2a5f9aSShuming Fan val |= (0x3 << 4);
9657d2a5f9aSShuming Fan break;
9667d2a5f9aSShuming Fan case 32:
9677d2a5f9aSShuming Fan val |= (0x4 << 4);
9687d2a5f9aSShuming Fan break;
9697d2a5f9aSShuming Fan default:
9707d2a5f9aSShuming Fan return -EINVAL;
9717d2a5f9aSShuming Fan }
9727d2a5f9aSShuming Fan
9737d2a5f9aSShuming Fan /* 48Khz */
9747d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_DAC_FORMAT_H, val);
9757d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_ADC_FORMAT_H, val);
9767d2a5f9aSShuming Fan
9777d2a5f9aSShuming Fan return retval;
9787d2a5f9aSShuming Fan }
9797d2a5f9aSShuming Fan
rt700_pcm_hw_free(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)9807d2a5f9aSShuming Fan static int rt700_pcm_hw_free(struct snd_pcm_substream *substream,
9817d2a5f9aSShuming Fan struct snd_soc_dai *dai)
9827d2a5f9aSShuming Fan {
9837d2a5f9aSShuming Fan struct snd_soc_component *component = dai->component;
9847d2a5f9aSShuming Fan struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
9853bcced01SPierre-Louis Bossart struct sdw_stream_runtime *sdw_stream =
9867d2a5f9aSShuming Fan snd_soc_dai_get_dma_data(dai, substream);
9877d2a5f9aSShuming Fan
9887d2a5f9aSShuming Fan if (!rt700->slave)
9897d2a5f9aSShuming Fan return -EINVAL;
9907d2a5f9aSShuming Fan
9913bcced01SPierre-Louis Bossart sdw_stream_remove_slave(rt700->slave, sdw_stream);
9927d2a5f9aSShuming Fan return 0;
9937d2a5f9aSShuming Fan }
9947d2a5f9aSShuming Fan
9957d2a5f9aSShuming Fan #define RT700_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
9967d2a5f9aSShuming Fan #define RT700_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
9977d2a5f9aSShuming Fan SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
9987d2a5f9aSShuming Fan
999f9e56a34SRikard Falkeborn static const struct snd_soc_dai_ops rt700_ops = {
10007d2a5f9aSShuming Fan .hw_params = rt700_pcm_hw_params,
10017d2a5f9aSShuming Fan .hw_free = rt700_pcm_hw_free,
1002e8444560SPierre-Louis Bossart .set_stream = rt700_set_sdw_stream,
10037d2a5f9aSShuming Fan .shutdown = rt700_shutdown,
10047d2a5f9aSShuming Fan };
10057d2a5f9aSShuming Fan
10067d2a5f9aSShuming Fan static struct snd_soc_dai_driver rt700_dai[] = {
10077d2a5f9aSShuming Fan {
10087d2a5f9aSShuming Fan .name = "rt700-aif1",
10097d2a5f9aSShuming Fan .id = RT700_AIF1,
10107d2a5f9aSShuming Fan .playback = {
10117d2a5f9aSShuming Fan .stream_name = "DP1 Playback",
10127d2a5f9aSShuming Fan .channels_min = 1,
10137d2a5f9aSShuming Fan .channels_max = 2,
10147d2a5f9aSShuming Fan .rates = RT700_STEREO_RATES,
10157d2a5f9aSShuming Fan .formats = RT700_FORMATS,
10167d2a5f9aSShuming Fan },
10177d2a5f9aSShuming Fan .capture = {
10187d2a5f9aSShuming Fan .stream_name = "DP2 Capture",
10197d2a5f9aSShuming Fan .channels_min = 1,
10207d2a5f9aSShuming Fan .channels_max = 2,
10217d2a5f9aSShuming Fan .rates = RT700_STEREO_RATES,
10227d2a5f9aSShuming Fan .formats = RT700_FORMATS,
10237d2a5f9aSShuming Fan },
10247d2a5f9aSShuming Fan .ops = &rt700_ops,
10257d2a5f9aSShuming Fan },
10267d2a5f9aSShuming Fan {
10277d2a5f9aSShuming Fan .name = "rt700-aif2",
10287d2a5f9aSShuming Fan .id = RT700_AIF2,
10297d2a5f9aSShuming Fan .playback = {
10307d2a5f9aSShuming Fan .stream_name = "DP3 Playback",
10317d2a5f9aSShuming Fan .channels_min = 1,
10327d2a5f9aSShuming Fan .channels_max = 2,
10337d2a5f9aSShuming Fan .rates = RT700_STEREO_RATES,
10347d2a5f9aSShuming Fan .formats = RT700_FORMATS,
10357d2a5f9aSShuming Fan },
10367d2a5f9aSShuming Fan .capture = {
10377d2a5f9aSShuming Fan .stream_name = "DP4 Capture",
10387d2a5f9aSShuming Fan .channels_min = 1,
10397d2a5f9aSShuming Fan .channels_max = 2,
10407d2a5f9aSShuming Fan .rates = RT700_STEREO_RATES,
10417d2a5f9aSShuming Fan .formats = RT700_FORMATS,
10427d2a5f9aSShuming Fan },
10437d2a5f9aSShuming Fan .ops = &rt700_ops,
10447d2a5f9aSShuming Fan },
10457d2a5f9aSShuming Fan };
10467d2a5f9aSShuming Fan
10477d2a5f9aSShuming Fan /* Bus clock frequency */
10487d2a5f9aSShuming Fan #define RT700_CLK_FREQ_9600000HZ 9600000
10497d2a5f9aSShuming Fan #define RT700_CLK_FREQ_12000000HZ 12000000
10507d2a5f9aSShuming Fan #define RT700_CLK_FREQ_6000000HZ 6000000
10517d2a5f9aSShuming Fan #define RT700_CLK_FREQ_4800000HZ 4800000
10527d2a5f9aSShuming Fan #define RT700_CLK_FREQ_2400000HZ 2400000
10537d2a5f9aSShuming Fan #define RT700_CLK_FREQ_12288000HZ 12288000
10547d2a5f9aSShuming Fan
rt700_clock_config(struct device * dev)10557d2a5f9aSShuming Fan int rt700_clock_config(struct device *dev)
10567d2a5f9aSShuming Fan {
10577d2a5f9aSShuming Fan struct rt700_priv *rt700 = dev_get_drvdata(dev);
10587d2a5f9aSShuming Fan unsigned int clk_freq, value;
10597d2a5f9aSShuming Fan
10607d2a5f9aSShuming Fan clk_freq = (rt700->params.curr_dr_freq >> 1);
10617d2a5f9aSShuming Fan
10627d2a5f9aSShuming Fan switch (clk_freq) {
10637d2a5f9aSShuming Fan case RT700_CLK_FREQ_12000000HZ:
10647d2a5f9aSShuming Fan value = 0x0;
10657d2a5f9aSShuming Fan break;
10667d2a5f9aSShuming Fan case RT700_CLK_FREQ_6000000HZ:
10677d2a5f9aSShuming Fan value = 0x1;
10687d2a5f9aSShuming Fan break;
10697d2a5f9aSShuming Fan case RT700_CLK_FREQ_9600000HZ:
10707d2a5f9aSShuming Fan value = 0x2;
10717d2a5f9aSShuming Fan break;
10727d2a5f9aSShuming Fan case RT700_CLK_FREQ_4800000HZ:
10737d2a5f9aSShuming Fan value = 0x3;
10747d2a5f9aSShuming Fan break;
10757d2a5f9aSShuming Fan case RT700_CLK_FREQ_2400000HZ:
10767d2a5f9aSShuming Fan value = 0x4;
10777d2a5f9aSShuming Fan break;
10787d2a5f9aSShuming Fan case RT700_CLK_FREQ_12288000HZ:
10797d2a5f9aSShuming Fan value = 0x5;
10807d2a5f9aSShuming Fan break;
10817d2a5f9aSShuming Fan default:
10827d2a5f9aSShuming Fan return -EINVAL;
10837d2a5f9aSShuming Fan }
10847d2a5f9aSShuming Fan
10857d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0xe0, value);
10867d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0xf0, value);
10877d2a5f9aSShuming Fan
10887d2a5f9aSShuming Fan dev_dbg(dev, "%s complete, clk_freq=%d\n", __func__, clk_freq);
10897d2a5f9aSShuming Fan
10907d2a5f9aSShuming Fan return 0;
10917d2a5f9aSShuming Fan }
10927d2a5f9aSShuming Fan
rt700_init(struct device * dev,struct regmap * sdw_regmap,struct regmap * regmap,struct sdw_slave * slave)10937d2a5f9aSShuming Fan int rt700_init(struct device *dev, struct regmap *sdw_regmap,
10947d2a5f9aSShuming Fan struct regmap *regmap, struct sdw_slave *slave)
10957d2a5f9aSShuming Fan
10967d2a5f9aSShuming Fan {
10977d2a5f9aSShuming Fan struct rt700_priv *rt700;
10987d2a5f9aSShuming Fan int ret;
10997d2a5f9aSShuming Fan
11007d2a5f9aSShuming Fan rt700 = devm_kzalloc(dev, sizeof(*rt700), GFP_KERNEL);
11017d2a5f9aSShuming Fan if (!rt700)
11027d2a5f9aSShuming Fan return -ENOMEM;
11037d2a5f9aSShuming Fan
11047d2a5f9aSShuming Fan dev_set_drvdata(dev, rt700);
11057d2a5f9aSShuming Fan rt700->slave = slave;
11067d2a5f9aSShuming Fan rt700->sdw_regmap = sdw_regmap;
11077d2a5f9aSShuming Fan rt700->regmap = regmap;
11087d2a5f9aSShuming Fan
110949ae74abSPierre-Louis Bossart regcache_cache_only(rt700->regmap, true);
111049ae74abSPierre-Louis Bossart
111160888ef8SPierre-Louis Bossart mutex_init(&rt700->disable_irq_lock);
111260888ef8SPierre-Louis Bossart
1113a49267a3SPierre-Louis Bossart INIT_DELAYED_WORK(&rt700->jack_detect_work,
1114a49267a3SPierre-Louis Bossart rt700_jack_detect_handler);
1115a49267a3SPierre-Louis Bossart INIT_DELAYED_WORK(&rt700->jack_btn_check_work,
1116a49267a3SPierre-Louis Bossart rt700_btn_check_handler);
1117a49267a3SPierre-Louis Bossart
11187d2a5f9aSShuming Fan /*
11197d2a5f9aSShuming Fan * Mark hw_init to false
11207d2a5f9aSShuming Fan * HW init will be performed when device reports present
11217d2a5f9aSShuming Fan */
11227d2a5f9aSShuming Fan rt700->hw_init = false;
11237d2a5f9aSShuming Fan rt700->first_hw_init = false;
11247d2a5f9aSShuming Fan
11257d2a5f9aSShuming Fan ret = devm_snd_soc_register_component(dev,
11267d2a5f9aSShuming Fan &soc_codec_dev_rt700,
11277d2a5f9aSShuming Fan rt700_dai,
11287d2a5f9aSShuming Fan ARRAY_SIZE(rt700_dai));
1129*6b8f8c5eSPierre-Louis Bossart if (ret < 0)
1130*6b8f8c5eSPierre-Louis Bossart return ret;
11317d2a5f9aSShuming Fan
1132*6b8f8c5eSPierre-Louis Bossart /* set autosuspend parameters */
1133*6b8f8c5eSPierre-Louis Bossart pm_runtime_set_autosuspend_delay(dev, 3000);
1134*6b8f8c5eSPierre-Louis Bossart pm_runtime_use_autosuspend(dev);
1135*6b8f8c5eSPierre-Louis Bossart
1136*6b8f8c5eSPierre-Louis Bossart /* make sure the device does not suspend immediately */
1137*6b8f8c5eSPierre-Louis Bossart pm_runtime_mark_last_busy(dev);
1138*6b8f8c5eSPierre-Louis Bossart
1139*6b8f8c5eSPierre-Louis Bossart pm_runtime_enable(dev);
1140*6b8f8c5eSPierre-Louis Bossart
1141*6b8f8c5eSPierre-Louis Bossart /* important note: the device is NOT tagged as 'active' and will remain
1142*6b8f8c5eSPierre-Louis Bossart * 'suspended' until the hardware is enumerated/initialized. This is required
1143*6b8f8c5eSPierre-Louis Bossart * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
1144*6b8f8c5eSPierre-Louis Bossart * fail with -EACCESS because of race conditions between card creation and enumeration
1145*6b8f8c5eSPierre-Louis Bossart */
11467d2a5f9aSShuming Fan dev_dbg(&slave->dev, "%s\n", __func__);
11477d2a5f9aSShuming Fan
1148*6b8f8c5eSPierre-Louis Bossart return 0;
11497d2a5f9aSShuming Fan }
11507d2a5f9aSShuming Fan
rt700_io_init(struct device * dev,struct sdw_slave * slave)11517d2a5f9aSShuming Fan int rt700_io_init(struct device *dev, struct sdw_slave *slave)
11527d2a5f9aSShuming Fan {
11537d2a5f9aSShuming Fan struct rt700_priv *rt700 = dev_get_drvdata(dev);
11547d2a5f9aSShuming Fan
115560888ef8SPierre-Louis Bossart rt700->disable_irq = false;
115660888ef8SPierre-Louis Bossart
11577d2a5f9aSShuming Fan if (rt700->hw_init)
11587d2a5f9aSShuming Fan return 0;
11597d2a5f9aSShuming Fan
11607d2a5f9aSShuming Fan regcache_cache_only(rt700->regmap, false);
116149ae74abSPierre-Louis Bossart if (rt700->first_hw_init)
11627d2a5f9aSShuming Fan regcache_cache_bypass(rt700->regmap, true);
11637d2a5f9aSShuming Fan
11647d2a5f9aSShuming Fan /*
11657d2a5f9aSShuming Fan * PM runtime is only enabled when a Slave reports as Attached
11667d2a5f9aSShuming Fan */
1167*6b8f8c5eSPierre-Louis Bossart if (!rt700->first_hw_init)
1168*6b8f8c5eSPierre-Louis Bossart /* PM runtime status is marked as 'active' only when a Slave reports as Attached */
11697d2a5f9aSShuming Fan pm_runtime_set_active(&slave->dev);
11707d2a5f9aSShuming Fan
11717d2a5f9aSShuming Fan pm_runtime_get_noresume(&slave->dev);
11727d2a5f9aSShuming Fan
11737d2a5f9aSShuming Fan /* reset */
11747d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0xff01, 0x0000);
11757d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x7520, 0x001a);
11767d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x7420, 0xc003);
11777d2a5f9aSShuming Fan
11787d2a5f9aSShuming Fan /* power on */
11797d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D0);
11807d2a5f9aSShuming Fan /* Set Pin Widget */
11817d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_SET_PIN_HP, 0x40);
11827d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_SET_PIN_SPK, 0x40);
11837d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_SET_EAPD_SPK, RT700_EAPD_HIGH);
11847d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_SET_PIN_DMIC1, 0x20);
11857d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_SET_PIN_DMIC2, 0x20);
11867d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_SET_PIN_MIC2, 0x20);
11877d2a5f9aSShuming Fan
11887d2a5f9aSShuming Fan /* Set Configuration Default */
11897d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4f12, 0x91);
11907d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4e12, 0xd6);
11917d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4d12, 0x11);
11927d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4c12, 0x20);
11937d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4f13, 0x91);
11947d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4e13, 0xd6);
11957d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4d13, 0x11);
11967d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4c13, 0x21);
11977d2a5f9aSShuming Fan
11987d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4f19, 0x02);
11997d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4e19, 0xa1);
12007d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4d19, 0x90);
12017d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x4c19, 0x80);
12027d2a5f9aSShuming Fan
12037d2a5f9aSShuming Fan /* Enable Line2 */
12047d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x371b, 0x40);
12057d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x731b, 0xb0);
12067d2a5f9aSShuming Fan regmap_write(rt700->regmap, 0x839b, 0x00);
12077d2a5f9aSShuming Fan
12087d2a5f9aSShuming Fan /* Set index */
12097d2a5f9aSShuming Fan rt700_index_write(rt700->regmap, 0x4a, 0x201b);
12107d2a5f9aSShuming Fan rt700_index_write(rt700->regmap, 0x45, 0x5089);
12117d2a5f9aSShuming Fan rt700_index_write(rt700->regmap, 0x6b, 0x5064);
12127d2a5f9aSShuming Fan rt700_index_write(rt700->regmap, 0x48, 0xd249);
12137d2a5f9aSShuming Fan
12147d2a5f9aSShuming Fan /* Finish Initial Settings, set power to D3 */
12157d2a5f9aSShuming Fan regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
12167d2a5f9aSShuming Fan
12177d2a5f9aSShuming Fan /*
12187d2a5f9aSShuming Fan * if set_jack callback occurred early than io_init,
12197d2a5f9aSShuming Fan * we set up the jack detection function now
12207d2a5f9aSShuming Fan */
12217d2a5f9aSShuming Fan if (rt700->hs_jack)
12227d2a5f9aSShuming Fan rt700_jack_init(rt700);
12237d2a5f9aSShuming Fan
12247d2a5f9aSShuming Fan if (rt700->first_hw_init) {
12257d2a5f9aSShuming Fan regcache_cache_bypass(rt700->regmap, false);
12267d2a5f9aSShuming Fan regcache_mark_dirty(rt700->regmap);
12277d2a5f9aSShuming Fan } else
12287d2a5f9aSShuming Fan rt700->first_hw_init = true;
12297d2a5f9aSShuming Fan
12307d2a5f9aSShuming Fan /* Mark Slave initialization complete */
12317d2a5f9aSShuming Fan rt700->hw_init = true;
12327d2a5f9aSShuming Fan
12337d2a5f9aSShuming Fan pm_runtime_mark_last_busy(&slave->dev);
12347d2a5f9aSShuming Fan pm_runtime_put_autosuspend(&slave->dev);
12357d2a5f9aSShuming Fan
12367d2a5f9aSShuming Fan dev_dbg(&slave->dev, "%s hw_init complete\n", __func__);
12377d2a5f9aSShuming Fan
12387d2a5f9aSShuming Fan return 0;
12397d2a5f9aSShuming Fan }
12407d2a5f9aSShuming Fan
12417d2a5f9aSShuming Fan MODULE_DESCRIPTION("ASoC RT700 driver SDW");
12427d2a5f9aSShuming Fan MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>");
12437d2a5f9aSShuming Fan MODULE_LICENSE("GPL v2");
1244