1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2020 Intel Corporation. All rights reserved. 4 5 #include <linux/device.h> 6 #include <linux/kernel.h> 7 #include <sound/pcm.h> 8 #include <sound/pcm_params.h> 9 #include <sound/soc.h> 10 #include <sound/soc-dai.h> 11 #include <sound/soc-dapm.h> 12 #include <uapi/sound/asound.h> 13 #include "../../codecs/rt1011.h" 14 #include "sof_realtek_common.h" 15 16 /* 17 * Current only 2-amp configuration is supported for rt1011 18 */ 19 static const struct snd_soc_dapm_route rt1011_dapm_routes[] = { 20 /* speaker */ 21 { "Left Spk", NULL, "Left SPO" }, 22 { "Right Spk", NULL, "Right SPO" }, 23 }; 24 25 /* 26 * Make sure device's Unique ID follows this configuration: 27 * 28 * Two speakers: 29 * 0: left, 1: right 30 * Four speakers: 31 * 0: Woofer left, 1: Woofer right 32 * 2: Tweeter left, 3: Tweeter right 33 */ 34 static struct snd_soc_codec_conf rt1011_codec_confs[] = { 35 { 36 .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME), 37 .name_prefix = "Left", 38 }, 39 { 40 .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME), 41 .name_prefix = "Right", 42 }, 43 }; 44 45 static struct snd_soc_dai_link_component rt1011_dai_link_components[] = { 46 { 47 .name = RT1011_DEV0_NAME, 48 .dai_name = RT1011_CODEC_DAI, 49 }, 50 { 51 .name = RT1011_DEV1_NAME, 52 .dai_name = RT1011_CODEC_DAI, 53 }, 54 }; 55 56 static const struct { 57 unsigned int tx; 58 unsigned int rx; 59 } rt1011_tdm_mask[] = { 60 {.tx = 0x4, .rx = 0x1}, 61 {.tx = 0x8, .rx = 0x2}, 62 }; 63 64 static int rt1011_hw_params(struct snd_pcm_substream *substream, 65 struct snd_pcm_hw_params *params) 66 { 67 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 68 struct snd_soc_dai *codec_dai; 69 int srate, i, ret = 0; 70 71 srate = params_rate(params); 72 73 for_each_rtd_codec_dais(rtd, i, codec_dai) { 74 /* 100 Fs to drive 24 bit data */ 75 ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK, 76 100 * srate, 256 * srate); 77 if (ret < 0) { 78 dev_err(codec_dai->dev, "fail to set pll, ret %d\n", 79 ret); 80 return ret; 81 } 82 83 ret = snd_soc_dai_set_sysclk(codec_dai, RT1011_FS_SYS_PRE_S_PLL1, 84 256 * srate, SND_SOC_CLOCK_IN); 85 if (ret < 0) { 86 dev_err(codec_dai->dev, "fail to set sysclk, ret %d\n", 87 ret); 88 return ret; 89 } 90 91 if (i >= ARRAY_SIZE(rt1011_tdm_mask)) { 92 dev_err(codec_dai->dev, "invalid codec index %d\n", 93 i); 94 return -ENODEV; 95 } 96 97 ret = snd_soc_dai_set_tdm_slot(codec_dai, rt1011_tdm_mask[i].tx, 98 rt1011_tdm_mask[i].rx, 4, 99 params_width(params)); 100 if (ret < 0) { 101 dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", 102 ret); 103 return ret; 104 } 105 } 106 107 return 0; 108 } 109 110 static const struct snd_soc_ops rt1011_ops = { 111 .hw_params = rt1011_hw_params, 112 }; 113 114 static int rt1011_init(struct snd_soc_pcm_runtime *rtd) 115 { 116 struct snd_soc_card *card = rtd->card; 117 int ret; 118 119 ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_dapm_routes, 120 ARRAY_SIZE(rt1011_dapm_routes)); 121 if (ret) 122 dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); 123 return ret; 124 } 125 126 void sof_rt1011_dai_link(struct snd_soc_dai_link *link) 127 { 128 link->codecs = rt1011_dai_link_components; 129 link->num_codecs = ARRAY_SIZE(rt1011_dai_link_components); 130 link->init = rt1011_init; 131 link->ops = &rt1011_ops; 132 } 133 134 void sof_rt1011_codec_conf(struct snd_soc_card *card) 135 { 136 card->codec_conf = rt1011_codec_confs; 137 card->num_configs = ARRAY_SIZE(rt1011_codec_confs); 138 } 139