f6bbea0d38105fd46074827e9377eadc78af0b94
[platform/kernel/linux-starfive.git] / sound / soc / intel / boards / sof_sdw_rt1316.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2020 Intel Corporation
3
4 /*
5  *  sof_sdw_rt1316 - Helpers to handle RT1316 from generic machine driver
6  */
7
8 #include <linux/device.h>
9 #include <linux/errno.h>
10 #include <sound/control.h>
11 #include <sound/soc.h>
12 #include <sound/soc-acpi.h>
13 #include <sound/soc-dapm.h>
14 #include <linux/soundwire/sdw.h>
15 #include <linux/soundwire/sdw_type.h>
16 #include <linux/dmi.h>
17 #include "sof_sdw_common.h"
18 #include "sof_sdw_amp_coeff_tables.h"
19
20 struct rt1316_platform_data {
21         const unsigned char *bq_params;
22         const unsigned int bq_params_cnt;
23 };
24
25 static const struct rt1316_platform_data dell_0b00_platform_data = {
26         .bq_params = dell_0b00_bq_params,
27         .bq_params_cnt = ARRAY_SIZE(dell_0b00_bq_params),
28 };
29
30 static const struct dmi_system_id dmi_platform_data[] = {
31         /* AlderLake devices */
32         {
33                 .matches = {
34                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
35                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
36                 },
37                 .driver_data = (void *)&dell_0b00_platform_data,
38         },
39         {
40                 .matches = {
41                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
42                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
43                 },
44                 .driver_data = (void *)&dell_0b00_platform_data,
45         },
46         {
47                 .matches = {
48                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
49                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF")
50                 },
51                 .driver_data = (void *)&dell_0b00_platform_data,
52         },
53         {
54                 .matches = {
55                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
56                         DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE")
57                 },
58                 .driver_data = (void *)&dell_0b00_platform_data,
59         },
60 };
61
62 static int rt1316_add_device_props(struct device *sdw_dev)
63 {
64         struct property_entry props[3] = {};
65         struct fwnode_handle *fwnode;
66         const struct dmi_system_id *dmi_data;
67         const struct rt1316_platform_data *pdata;
68         unsigned char params[RT1316_MAX_BQ_REG];
69         int ret;
70
71         dmi_data = dmi_first_match(dmi_platform_data);
72         if (!dmi_data)
73                 return 0;
74
75         pdata = dmi_data->driver_data;
76         memcpy(&params, pdata->bq_params, sizeof(unsigned char) * pdata->bq_params_cnt);
77
78         props[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params);
79         props[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata->bq_params_cnt);
80
81         fwnode = fwnode_create_software_node(props, NULL);
82         if (IS_ERR(fwnode))
83                 return PTR_ERR(fwnode);
84
85         ret = device_add_software_node(sdw_dev, to_software_node(fwnode));
86
87         fwnode_handle_put(fwnode);
88
89         return ret;
90 }
91
92 static const struct snd_soc_dapm_widget rt1316_widgets[] = {
93         SND_SOC_DAPM_SPK("Speaker", NULL),
94 };
95
96 /*
97  * dapm routes for rt1316 will be registered dynamically according
98  * to the number of rt1316 used. The first two entries will be registered
99  * for one codec case, and the last two entries are also registered
100  * if two 1316s are used.
101  */
102 static const struct snd_soc_dapm_route rt1316_map[] = {
103         { "Speaker", NULL, "rt1316-1 SPOL" },
104         { "Speaker", NULL, "rt1316-1 SPOR" },
105         { "Speaker", NULL, "rt1316-2 SPOL" },
106         { "Speaker", NULL, "rt1316-2 SPOR" },
107 };
108
109 static const struct snd_kcontrol_new rt1316_controls[] = {
110         SOC_DAPM_PIN_SWITCH("Speaker"),
111 };
112
113 static int first_spk_init(struct snd_soc_pcm_runtime *rtd)
114 {
115         struct snd_soc_card *card = rtd->card;
116         int ret;
117
118         card->components = devm_kasprintf(card->dev, GFP_KERNEL,
119                                           "%s spk:rt1316",
120                                           card->components);
121         if (!card->components)
122                 return -ENOMEM;
123
124         ret = snd_soc_add_card_controls(card, rt1316_controls,
125                                         ARRAY_SIZE(rt1316_controls));
126         if (ret) {
127                 dev_err(card->dev, "rt1316 controls addition failed: %d\n", ret);
128                 return ret;
129         }
130
131         ret = snd_soc_dapm_new_controls(&card->dapm, rt1316_widgets,
132                                         ARRAY_SIZE(rt1316_widgets));
133         if (ret) {
134                 dev_err(card->dev, "rt1316 widgets addition failed: %d\n", ret);
135                 return ret;
136         }
137
138         ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map, 2);
139         if (ret)
140                 dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret);
141
142         return ret;
143 }
144
145 static int second_spk_init(struct snd_soc_pcm_runtime *rtd)
146 {
147         struct snd_soc_card *card = rtd->card;
148         int ret;
149
150         ret = snd_soc_dapm_add_routes(&card->dapm, rt1316_map + 2, 2);
151         if (ret)
152                 dev_err(rtd->dev, "failed to add second SPK map: %d\n", ret);
153
154         return ret;
155 }
156
157 static int all_spk_init(struct snd_soc_pcm_runtime *rtd)
158 {
159         int ret;
160
161         ret = first_spk_init(rtd);
162         if (ret)
163                 return ret;
164
165         return second_spk_init(rtd);
166 }
167
168 int sof_sdw_rt1316_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)
169 {
170         struct mc_private *ctx = snd_soc_card_get_drvdata(card);
171
172         if (ctx->amp_dev1) {
173                 device_remove_software_node(ctx->amp_dev1);
174                 put_device(ctx->amp_dev1);
175         }
176
177         if (ctx->amp_dev2) {
178                 device_remove_software_node(ctx->amp_dev2);
179                 put_device(ctx->amp_dev2);
180         }
181
182         return 0;
183 }
184
185 int sof_sdw_rt1316_init(struct snd_soc_card *card,
186                         const struct snd_soc_acpi_link_adr *link,
187                         struct snd_soc_dai_link *dai_links,
188                         struct sof_sdw_codec_info *info,
189                         bool playback)
190 {
191         struct mc_private *ctx = snd_soc_card_get_drvdata(card);
192         struct device *sdw_dev1, *sdw_dev2;
193         int ret;
194
195         /* Count amp number and do init on playback link only. */
196         if (!playback)
197                 return 0;
198
199         info->amp_num++;
200         if (info->amp_num == 1)
201                 dai_links->init = first_spk_init;
202
203         if (info->amp_num == 2) {
204                 sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name);
205                 if (!sdw_dev1)
206                         return -EPROBE_DEFER;
207
208                 ret = rt1316_add_device_props(sdw_dev1);
209                 if (ret < 0) {
210                         put_device(sdw_dev1);
211                         return ret;
212                 }
213                 ctx->amp_dev1 = sdw_dev1;
214
215                 sdw_dev2 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[1].name);
216                 if (!sdw_dev2)
217                         return -EPROBE_DEFER;
218
219                 ret = rt1316_add_device_props(sdw_dev2);
220                 if (ret < 0) {
221                         put_device(sdw_dev2);
222                         return ret;
223                 }
224                 ctx->amp_dev2 = sdw_dev2;
225
226                 /*
227                  * if two 1316s are in one dai link, the init function
228                  * in this dai link will be first set for the first speaker,
229                  * and it should be reset to initialize all speakers when
230                  * the second speaker is found.
231                  */
232                 if (dai_links->init)
233                         dai_links->init = all_spk_init;
234                 else
235                         dai_links->init = second_spk_init;
236         }
237
238         return 0;
239 }