Commit | Line | Data |
---|---|---|
5be27f1e SD |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // TAS2781 HDA I2C driver | |
4 | // | |
3beddef8 | 5 | // Copyright 2023 - 2024 Texas Instruments, Inc. |
5be27f1e SD |
6 | // |
7 | // Author: Shenghao Ding <shenghao-ding@ti.com> | |
3beddef8 | 8 | // Current maintainer: Baojun Xu <baojun.xu@ti.com> |
5be27f1e | 9 | |
5f60d5f6 | 10 | #include <linux/unaligned.h> |
5be27f1e SD |
11 | #include <linux/acpi.h> |
12 | #include <linux/crc8.h> | |
13 | #include <linux/crc32.h> | |
14 | #include <linux/efi.h> | |
15 | #include <linux/firmware.h> | |
16 | #include <linux/i2c.h> | |
17 | #include <linux/mod_devicetable.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/pm_runtime.h> | |
20 | #include <linux/regmap.h> | |
21 | #include <sound/hda_codec.h> | |
22 | #include <sound/soc.h> | |
23 | #include <sound/tas2781.h> | |
24 | #include <sound/tlv.h> | |
25 | #include <sound/tas2781-tlv.h> | |
26 | ||
27 | #include "hda_local.h" | |
28 | #include "hda_auto_parser.h" | |
29 | #include "hda_component.h" | |
30 | #include "hda_jack.h" | |
31 | #include "hda_generic.h" | |
32 | ||
33 | #define TASDEVICE_SPEAKER_CALIBRATION_SIZE 20 | |
34 | ||
35 | /* No standard control callbacks for SNDRV_CTL_ELEM_IFACE_CARD | |
36 | * Define two controls, one is Volume control callbacks, the other is | |
37 | * flag setting control callbacks. | |
38 | */ | |
39 | ||
40 | /* Volume control callbacks for tas2781 */ | |
41 | #define ACARD_SINGLE_RANGE_EXT_TLV(xname, xreg, xshift, xmin, xmax, xinvert, \ | |
42 | xhandler_get, xhandler_put, tlv_array) \ | |
43 | { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = (xname),\ | |
44 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | |
45 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | |
46 | .tlv.p = (tlv_array), \ | |
47 | .info = snd_soc_info_volsw_range, \ | |
48 | .get = xhandler_get, .put = xhandler_put, \ | |
49 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | |
50 | {.reg = xreg, .rreg = xreg, .shift = xshift, \ | |
51 | .rshift = xshift, .min = xmin, .max = xmax, \ | |
52 | .invert = xinvert} } | |
53 | ||
54 | /* Flag control callbacks for tas2781 */ | |
55 | #define ACARD_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ | |
56 | { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = xname, \ | |
57 | .info = snd_ctl_boolean_mono_info, \ | |
58 | .get = xhandler_get, .put = xhandler_put, \ | |
59 | .private_value = xdata } | |
60 | ||
61 | enum calib_data { | |
62 | R0_VAL = 0, | |
63 | INV_R0, | |
64 | R0LOW, | |
65 | POWER, | |
66 | TLIM, | |
67 | CALIB_MAX | |
68 | }; | |
69 | ||
c3ca4458 GK |
70 | #define TAS2563_MAX_CHANNELS 4 |
71 | ||
72 | #define TAS2563_CAL_POWER TASDEVICE_REG(0, 0x0d, 0x3c) | |
73 | #define TAS2563_CAL_R0 TASDEVICE_REG(0, 0x0f, 0x34) | |
74 | #define TAS2563_CAL_INVR0 TASDEVICE_REG(0, 0x0f, 0x40) | |
75 | #define TAS2563_CAL_R0_LOW TASDEVICE_REG(0, 0x0f, 0x48) | |
76 | #define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14) | |
77 | #define TAS2563_CAL_N 5 | |
78 | #define TAS2563_CAL_DATA_SIZE 4 | |
79 | #define TAS2563_CAL_CH_SIZE 20 | |
80 | #define TAS2563_CAL_ARRAY_SIZE 80 | |
81 | ||
82 | static unsigned int cal_regs[TAS2563_CAL_N] = { | |
83 | TAS2563_CAL_POWER, TAS2563_CAL_R0, TAS2563_CAL_INVR0, | |
84 | TAS2563_CAL_R0_LOW, TAS2563_CAL_TLIM, | |
85 | }; | |
86 | ||
87 | ||
4e7914eb GK |
88 | struct tas2781_hda { |
89 | struct device *dev; | |
90 | struct tasdevice_priv *priv; | |
91 | struct snd_kcontrol *dsp_prog_ctl; | |
92 | struct snd_kcontrol *dsp_conf_ctl; | |
93 | struct snd_kcontrol *prof_ctl; | |
ae065d0c | 94 | struct snd_kcontrol *snd_ctls[2]; |
4e7914eb GK |
95 | }; |
96 | ||
5be27f1e SD |
97 | static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) |
98 | { | |
99 | struct tasdevice_priv *tas_priv = data; | |
100 | struct acpi_resource_i2c_serialbus *sb; | |
101 | ||
102 | if (i2c_acpi_get_i2c_resource(ares, &sb)) { | |
103 | if (tas_priv->ndev < TASDEVICE_MAX_CHANNELS && | |
c021ca72 | 104 | sb->slave_address != tas_priv->global_addr) { |
5be27f1e SD |
105 | tas_priv->tasdevice[tas_priv->ndev].dev_addr = |
106 | (unsigned int)sb->slave_address; | |
107 | tas_priv->ndev++; | |
108 | } | |
109 | } | |
110 | return 1; | |
111 | } | |
112 | ||
113 | static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) | |
114 | { | |
115 | struct acpi_device *adev; | |
5be27f1e | 116 | LIST_HEAD(resources); |
5be27f1e SD |
117 | int ret; |
118 | ||
119 | adev = acpi_dev_get_first_match_dev(hid, NULL, -1); | |
120 | if (!adev) { | |
121 | dev_err(p->dev, | |
122 | "Failed to find an ACPI device for %s\n", hid); | |
123 | return -ENODEV; | |
124 | } | |
125 | ||
126 | ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p); | |
127 | if (ret < 0) | |
128 | goto err; | |
129 | ||
130 | acpi_dev_free_resource_list(&resources); | |
131 | strscpy(p->dev_name, hid, sizeof(p->dev_name)); | |
5be27f1e SD |
132 | acpi_dev_put(adev); |
133 | ||
5be27f1e SD |
134 | return 0; |
135 | ||
136 | err: | |
137 | dev_err(p->dev, "read acpi error, ret: %d\n", ret); | |
1c80cc05 | 138 | acpi_dev_put(adev); |
5be27f1e SD |
139 | |
140 | return ret; | |
141 | } | |
142 | ||
143 | static void tas2781_hda_playback_hook(struct device *dev, int action) | |
144 | { | |
4e7914eb | 145 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5be27f1e | 146 | |
4e7914eb | 147 | dev_dbg(tas_hda->dev, "%s: action = %d\n", __func__, action); |
5be27f1e SD |
148 | switch (action) { |
149 | case HDA_GEN_PCM_ACT_OPEN: | |
150 | pm_runtime_get_sync(dev); | |
4e7914eb GK |
151 | mutex_lock(&tas_hda->priv->codec_lock); |
152 | tasdevice_tuning_switch(tas_hda->priv, 0); | |
9fc91a6f | 153 | tas_hda->priv->playback_started = true; |
4e7914eb | 154 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e SD |
155 | break; |
156 | case HDA_GEN_PCM_ACT_CLOSE: | |
4e7914eb GK |
157 | mutex_lock(&tas_hda->priv->codec_lock); |
158 | tasdevice_tuning_switch(tas_hda->priv, 1); | |
9fc91a6f | 159 | tas_hda->priv->playback_started = false; |
4e7914eb | 160 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e SD |
161 | |
162 | pm_runtime_mark_last_busy(dev); | |
163 | pm_runtime_put_autosuspend(dev); | |
164 | break; | |
165 | default: | |
5be27f1e SD |
166 | break; |
167 | } | |
168 | } | |
169 | ||
170 | static int tasdevice_info_profile(struct snd_kcontrol *kcontrol, | |
171 | struct snd_ctl_elem_info *uinfo) | |
172 | { | |
173 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
174 | ||
175 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
176 | uinfo->count = 1; | |
177 | uinfo->value.integer.min = 0; | |
178 | uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1; | |
179 | ||
180 | return 0; | |
181 | } | |
182 | ||
183 | static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol, | |
184 | struct snd_ctl_elem_value *ucontrol) | |
185 | { | |
186 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
187 | ||
15bc3066 GK |
188 | mutex_lock(&tas_priv->codec_lock); |
189 | ||
5be27f1e SD |
190 | ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id; |
191 | ||
26c04a8a GK |
192 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", |
193 | __func__, kcontrol->id.name, tas_priv->rcabin.profile_cfg_id); | |
194 | ||
15bc3066 GK |
195 | mutex_unlock(&tas_priv->codec_lock); |
196 | ||
5be27f1e SD |
197 | return 0; |
198 | } | |
199 | ||
5be27f1e SD |
200 | static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol, |
201 | struct snd_ctl_elem_value *ucontrol) | |
202 | { | |
203 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
204 | int nr_profile = ucontrol->value.integer.value[0]; | |
205 | int max = tas_priv->rcabin.ncfgs - 1; | |
206 | int val, ret = 0; | |
207 | ||
da42bcb3 | 208 | val = clamp(nr_profile, 0, max); |
5be27f1e | 209 | |
15bc3066 GK |
210 | mutex_lock(&tas_priv->codec_lock); |
211 | ||
26c04a8a GK |
212 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", |
213 | __func__, kcontrol->id.name, | |
214 | tas_priv->rcabin.profile_cfg_id, val); | |
215 | ||
5be27f1e SD |
216 | if (tas_priv->rcabin.profile_cfg_id != val) { |
217 | tas_priv->rcabin.profile_cfg_id = val; | |
218 | ret = 1; | |
219 | } | |
220 | ||
15bc3066 GK |
221 | mutex_unlock(&tas_priv->codec_lock); |
222 | ||
5be27f1e SD |
223 | return ret; |
224 | } | |
225 | ||
226 | static int tasdevice_info_programs(struct snd_kcontrol *kcontrol, | |
227 | struct snd_ctl_elem_info *uinfo) | |
228 | { | |
229 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
230 | struct tasdevice_fw *tas_fw = tas_priv->fmw; | |
231 | ||
232 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
233 | uinfo->count = 1; | |
234 | uinfo->value.integer.min = 0; | |
235 | uinfo->value.integer.max = tas_fw->nr_programs - 1; | |
236 | ||
237 | return 0; | |
238 | } | |
239 | ||
240 | static int tasdevice_info_config(struct snd_kcontrol *kcontrol, | |
241 | struct snd_ctl_elem_info *uinfo) | |
242 | { | |
243 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
244 | struct tasdevice_fw *tas_fw = tas_priv->fmw; | |
245 | ||
246 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
247 | uinfo->count = 1; | |
248 | uinfo->value.integer.min = 0; | |
249 | uinfo->value.integer.max = tas_fw->nr_configurations - 1; | |
250 | ||
251 | return 0; | |
252 | } | |
253 | ||
254 | static int tasdevice_program_get(struct snd_kcontrol *kcontrol, | |
255 | struct snd_ctl_elem_value *ucontrol) | |
256 | { | |
257 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
258 | ||
15bc3066 GK |
259 | mutex_lock(&tas_priv->codec_lock); |
260 | ||
5be27f1e SD |
261 | ucontrol->value.integer.value[0] = tas_priv->cur_prog; |
262 | ||
26c04a8a GK |
263 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", |
264 | __func__, kcontrol->id.name, tas_priv->cur_prog); | |
265 | ||
15bc3066 GK |
266 | mutex_unlock(&tas_priv->codec_lock); |
267 | ||
5be27f1e SD |
268 | return 0; |
269 | } | |
270 | ||
271 | static int tasdevice_program_put(struct snd_kcontrol *kcontrol, | |
272 | struct snd_ctl_elem_value *ucontrol) | |
273 | { | |
274 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
275 | struct tasdevice_fw *tas_fw = tas_priv->fmw; | |
276 | int nr_program = ucontrol->value.integer.value[0]; | |
277 | int max = tas_fw->nr_programs - 1; | |
278 | int val, ret = 0; | |
279 | ||
da42bcb3 | 280 | val = clamp(nr_program, 0, max); |
5be27f1e | 281 | |
15bc3066 GK |
282 | mutex_lock(&tas_priv->codec_lock); |
283 | ||
26c04a8a GK |
284 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", |
285 | __func__, kcontrol->id.name, tas_priv->cur_prog, val); | |
286 | ||
5be27f1e SD |
287 | if (tas_priv->cur_prog != val) { |
288 | tas_priv->cur_prog = val; | |
289 | ret = 1; | |
290 | } | |
291 | ||
15bc3066 GK |
292 | mutex_unlock(&tas_priv->codec_lock); |
293 | ||
5be27f1e SD |
294 | return ret; |
295 | } | |
296 | ||
297 | static int tasdevice_config_get(struct snd_kcontrol *kcontrol, | |
298 | struct snd_ctl_elem_value *ucontrol) | |
299 | { | |
300 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
301 | ||
15bc3066 GK |
302 | mutex_lock(&tas_priv->codec_lock); |
303 | ||
5be27f1e SD |
304 | ucontrol->value.integer.value[0] = tas_priv->cur_conf; |
305 | ||
26c04a8a GK |
306 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", |
307 | __func__, kcontrol->id.name, tas_priv->cur_conf); | |
308 | ||
15bc3066 GK |
309 | mutex_unlock(&tas_priv->codec_lock); |
310 | ||
5be27f1e SD |
311 | return 0; |
312 | } | |
313 | ||
314 | static int tasdevice_config_put(struct snd_kcontrol *kcontrol, | |
315 | struct snd_ctl_elem_value *ucontrol) | |
316 | { | |
317 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
318 | struct tasdevice_fw *tas_fw = tas_priv->fmw; | |
319 | int nr_config = ucontrol->value.integer.value[0]; | |
320 | int max = tas_fw->nr_configurations - 1; | |
321 | int val, ret = 0; | |
322 | ||
da42bcb3 | 323 | val = clamp(nr_config, 0, max); |
5be27f1e | 324 | |
15bc3066 GK |
325 | mutex_lock(&tas_priv->codec_lock); |
326 | ||
26c04a8a GK |
327 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", |
328 | __func__, kcontrol->id.name, tas_priv->cur_conf, val); | |
329 | ||
5be27f1e SD |
330 | if (tas_priv->cur_conf != val) { |
331 | tas_priv->cur_conf = val; | |
332 | ret = 1; | |
333 | } | |
334 | ||
15bc3066 GK |
335 | mutex_unlock(&tas_priv->codec_lock); |
336 | ||
5be27f1e SD |
337 | return ret; |
338 | } | |
339 | ||
5be27f1e SD |
340 | static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol, |
341 | struct snd_ctl_elem_value *ucontrol) | |
342 | { | |
343 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
344 | struct soc_mixer_control *mc = | |
345 | (struct soc_mixer_control *)kcontrol->private_value; | |
15bc3066 | 346 | int ret; |
5be27f1e | 347 | |
15bc3066 GK |
348 | mutex_lock(&tas_priv->codec_lock); |
349 | ||
350 | ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc); | |
351 | ||
26c04a8a GK |
352 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n", |
353 | __func__, kcontrol->id.name, ucontrol->value.integer.value[0]); | |
354 | ||
15bc3066 GK |
355 | mutex_unlock(&tas_priv->codec_lock); |
356 | ||
357 | return ret; | |
5be27f1e SD |
358 | } |
359 | ||
5be27f1e SD |
360 | static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, |
361 | struct snd_ctl_elem_value *ucontrol) | |
362 | { | |
363 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
364 | struct soc_mixer_control *mc = | |
365 | (struct soc_mixer_control *)kcontrol->private_value; | |
15bc3066 GK |
366 | int ret; |
367 | ||
368 | mutex_lock(&tas_priv->codec_lock); | |
5be27f1e | 369 | |
26c04a8a GK |
370 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n", |
371 | __func__, kcontrol->id.name, ucontrol->value.integer.value[0]); | |
372 | ||
5be27f1e | 373 | /* The check of the given value is in tasdevice_amp_putvol. */ |
15bc3066 GK |
374 | ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc); |
375 | ||
376 | mutex_unlock(&tas_priv->codec_lock); | |
377 | ||
378 | return ret; | |
5be27f1e SD |
379 | } |
380 | ||
381 | static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, | |
382 | struct snd_ctl_elem_value *ucontrol) | |
383 | { | |
384 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
385 | ||
15bc3066 GK |
386 | mutex_lock(&tas_priv->codec_lock); |
387 | ||
5be27f1e | 388 | ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status; |
26c04a8a GK |
389 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", |
390 | __func__, kcontrol->id.name, tas_priv->force_fwload_status); | |
5be27f1e | 391 | |
15bc3066 GK |
392 | mutex_unlock(&tas_priv->codec_lock); |
393 | ||
5be27f1e SD |
394 | return 0; |
395 | } | |
396 | ||
397 | static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, | |
398 | struct snd_ctl_elem_value *ucontrol) | |
399 | { | |
400 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
401 | bool change, val = (bool)ucontrol->value.integer.value[0]; | |
402 | ||
15bc3066 GK |
403 | mutex_lock(&tas_priv->codec_lock); |
404 | ||
26c04a8a GK |
405 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", |
406 | __func__, kcontrol->id.name, | |
407 | tas_priv->force_fwload_status, val); | |
408 | ||
5be27f1e SD |
409 | if (tas_priv->force_fwload_status == val) |
410 | change = false; | |
411 | else { | |
412 | change = true; | |
413 | tas_priv->force_fwload_status = val; | |
414 | } | |
5be27f1e | 415 | |
15bc3066 GK |
416 | mutex_unlock(&tas_priv->codec_lock); |
417 | ||
5be27f1e SD |
418 | return change; |
419 | } | |
420 | ||
421 | static const struct snd_kcontrol_new tas2781_snd_controls[] = { | |
422 | ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL, | |
423 | 1, 0, 20, 0, tas2781_amp_getvol, | |
424 | tas2781_amp_putvol, amp_vol_tlv), | |
5be27f1e SD |
425 | ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, |
426 | tas2781_force_fwload_get, tas2781_force_fwload_put), | |
427 | }; | |
428 | ||
429 | static const struct snd_kcontrol_new tas2781_prof_ctrl = { | |
430 | .name = "Speaker Profile Id", | |
431 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | |
432 | .info = tasdevice_info_profile, | |
433 | .get = tasdevice_get_profile_id, | |
434 | .put = tasdevice_set_profile_id, | |
435 | }; | |
436 | ||
437 | static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl = { | |
438 | .name = "Speaker Program Id", | |
439 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | |
440 | .info = tasdevice_info_programs, | |
441 | .get = tasdevice_program_get, | |
442 | .put = tasdevice_program_put, | |
443 | }; | |
444 | ||
445 | static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl = { | |
446 | .name = "Speaker Config Id", | |
447 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | |
448 | .info = tasdevice_info_config, | |
449 | .get = tasdevice_config_get, | |
450 | .put = tasdevice_config_put, | |
451 | }; | |
452 | ||
c3ca4458 GK |
453 | static void tas2563_apply_calib(struct tasdevice_priv *tas_priv) |
454 | { | |
c3ca4458 | 455 | int offset = 0; |
dcaca1b5 | 456 | __be32 data; |
c3ca4458 GK |
457 | int ret; |
458 | ||
459 | for (int i = 0; i < tas_priv->ndev; i++) { | |
460 | for (int j = 0; j < TAS2563_CAL_N; ++j) { | |
461 | data = cpu_to_be32( | |
462 | *(uint32_t *)&tas_priv->cali_data.data[offset]); | |
463 | ret = tasdevice_dev_bulk_write(tas_priv, i, cal_regs[j], | |
464 | (unsigned char *)&data, TAS2563_CAL_DATA_SIZE); | |
465 | if (ret) | |
466 | dev_err(tas_priv->dev, | |
467 | "Error writing calib regs\n"); | |
468 | offset += TAS2563_CAL_DATA_SIZE; | |
469 | } | |
470 | } | |
471 | } | |
472 | ||
473 | static int tas2563_save_calibration(struct tasdevice_priv *tas_priv) | |
474 | { | |
475 | static efi_guid_t efi_guid = EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, | |
476 | 0x09, 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92); | |
477 | ||
478 | static efi_char16_t *efi_vars[TAS2563_MAX_CHANNELS][TAS2563_CAL_N] = { | |
479 | { L"Power_1", L"R0_1", L"InvR0_1", L"R0_Low_1", L"TLim_1" }, | |
480 | { L"Power_2", L"R0_2", L"InvR0_2", L"R0_Low_2", L"TLim_2" }, | |
481 | { L"Power_3", L"R0_3", L"InvR0_3", L"R0_Low_3", L"TLim_3" }, | |
482 | { L"Power_4", L"R0_4", L"InvR0_4", L"R0_Low_4", L"TLim_4" }, | |
483 | }; | |
484 | ||
485 | unsigned long max_size = TAS2563_CAL_DATA_SIZE; | |
486 | unsigned int offset = 0; | |
487 | efi_status_t status; | |
488 | unsigned int attr; | |
489 | ||
490 | tas_priv->cali_data.data = devm_kzalloc(tas_priv->dev, | |
491 | TAS2563_CAL_ARRAY_SIZE, GFP_KERNEL); | |
492 | if (!tas_priv->cali_data.data) | |
493 | return -ENOMEM; | |
494 | ||
495 | for (int i = 0; i < tas_priv->ndev; ++i) { | |
496 | for (int j = 0; j < TAS2563_CAL_N; ++j) { | |
497 | status = efi.get_variable(efi_vars[i][j], | |
498 | &efi_guid, &attr, &max_size, | |
499 | &tas_priv->cali_data.data[offset]); | |
500 | if (status != EFI_SUCCESS || | |
501 | max_size != TAS2563_CAL_DATA_SIZE) { | |
502 | dev_warn(tas_priv->dev, | |
503 | "Calibration data read failed %ld\n", status); | |
504 | return -EINVAL; | |
505 | } | |
506 | offset += TAS2563_CAL_DATA_SIZE; | |
507 | } | |
508 | } | |
509 | ||
510 | tas_priv->cali_data.total_sz = offset; | |
511 | tasdevice_apply_calibration(tas_priv); | |
512 | ||
513 | return 0; | |
514 | } | |
515 | ||
5be27f1e SD |
516 | static void tas2781_apply_calib(struct tasdevice_priv *tas_priv) |
517 | { | |
518 | static const unsigned char page_array[CALIB_MAX] = { | |
0b6f0ff0 | 519 | 0x17, 0x18, 0x18, 0x13, 0x18, |
5be27f1e SD |
520 | }; |
521 | static const unsigned char rgno_array[CALIB_MAX] = { | |
0b6f0ff0 | 522 | 0x74, 0x0c, 0x14, 0x70, 0x7c, |
5be27f1e | 523 | }; |
3beddef8 | 524 | int offset = 0; |
5be27f1e | 525 | int i, j, rc; |
3beddef8 | 526 | __be32 data; |
5be27f1e SD |
527 | |
528 | for (i = 0; i < tas_priv->ndev; i++) { | |
5be27f1e | 529 | for (j = 0; j < CALIB_MAX; j++) { |
829e2a23 TI |
530 | data = cpu_to_be32( |
531 | *(uint32_t *)&tas_priv->cali_data.data[offset]); | |
5be27f1e SD |
532 | rc = tasdevice_dev_bulk_write(tas_priv, i, |
533 | TASDEVICE_REG(0, page_array[j], rgno_array[j]), | |
3beddef8 | 534 | (unsigned char *)&data, 4); |
5be27f1e SD |
535 | if (rc < 0) |
536 | dev_err(tas_priv->dev, | |
537 | "chn %d calib %d bulk_wr err = %d\n", | |
538 | i, j, rc); | |
3beddef8 | 539 | offset += 4; |
5be27f1e SD |
540 | } |
541 | } | |
542 | } | |
543 | ||
a0c9f7f2 | 544 | /* Update the calibration data, including speaker impedance, f0, etc, into algo. |
5be27f1e | 545 | * Calibrate data is done by manufacturer in the factory. These data are used |
a0c9f7f2 | 546 | * by Algo for calculating the speaker temperature, speaker membrane excursion |
5be27f1e SD |
547 | * and f0 in real time during playback. |
548 | */ | |
549 | static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) | |
550 | { | |
551 | efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, | |
552 | 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3); | |
553 | static efi_char16_t efi_name[] = L"CALI_DATA"; | |
554 | struct tm *tm = &tas_priv->tm; | |
555 | unsigned int attr, crc; | |
556 | unsigned int *tmp_val; | |
557 | efi_status_t status; | |
558 | ||
559 | /* Lenovo devices */ | |
560 | if (tas_priv->catlog_id == LENOVO) | |
561 | efi_guid = EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, 0x09, | |
562 | 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92); | |
563 | ||
564 | tas_priv->cali_data.total_sz = 0; | |
565 | /* Get real size of UEFI variable */ | |
566 | status = efi.get_variable(efi_name, &efi_guid, &attr, | |
567 | &tas_priv->cali_data.total_sz, tas_priv->cali_data.data); | |
568 | if (status == EFI_BUFFER_TOO_SMALL) { | |
569 | /* Allocate data buffer of data_size bytes */ | |
570 | tas_priv->cali_data.data = devm_kzalloc(tas_priv->dev, | |
571 | tas_priv->cali_data.total_sz, GFP_KERNEL); | |
572 | if (!tas_priv->cali_data.data) | |
573 | return -ENOMEM; | |
574 | /* Get variable contents into buffer */ | |
575 | status = efi.get_variable(efi_name, &efi_guid, &attr, | |
576 | &tas_priv->cali_data.total_sz, | |
577 | tas_priv->cali_data.data); | |
5be27f1e | 578 | } |
33071422 GK |
579 | if (status != EFI_SUCCESS) |
580 | return -EINVAL; | |
5be27f1e SD |
581 | |
582 | tmp_val = (unsigned int *)tas_priv->cali_data.data; | |
583 | ||
584 | crc = crc32(~0, tas_priv->cali_data.data, 84) ^ ~0; | |
585 | dev_dbg(tas_priv->dev, "cali crc 0x%08x PK tmp_val 0x%08x\n", | |
586 | crc, tmp_val[21]); | |
587 | ||
588 | if (crc == tmp_val[21]) { | |
589 | time64_to_tm(tmp_val[20], 0, tm); | |
590 | dev_dbg(tas_priv->dev, "%4ld-%2d-%2d, %2d:%2d:%2d\n", | |
591 | tm->tm_year, tm->tm_mon, tm->tm_mday, | |
592 | tm->tm_hour, tm->tm_min, tm->tm_sec); | |
76f5f55c | 593 | tasdevice_apply_calibration(tas_priv); |
5be27f1e SD |
594 | } else |
595 | tas_priv->cali_data.total_sz = 0; | |
596 | ||
597 | return 0; | |
598 | } | |
599 | ||
4e7914eb GK |
600 | static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) |
601 | { | |
602 | struct hda_codec *codec = tas_hda->priv->codec; | |
603 | ||
9d67a400 TI |
604 | snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl); |
605 | snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl); | |
4e7914eb GK |
606 | |
607 | for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--) | |
9d67a400 | 608 | snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]); |
4e7914eb | 609 | |
9d67a400 | 610 | snd_ctl_remove(codec->card, tas_hda->prof_ctl); |
4e7914eb GK |
611 | } |
612 | ||
5be27f1e SD |
613 | static void tasdev_fw_ready(const struct firmware *fmw, void *context) |
614 | { | |
615 | struct tasdevice_priv *tas_priv = context; | |
4e7914eb | 616 | struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); |
5be27f1e SD |
617 | struct hda_codec *codec = tas_priv->codec; |
618 | int i, ret; | |
619 | ||
620 | pm_runtime_get_sync(tas_priv->dev); | |
621 | mutex_lock(&tas_priv->codec_lock); | |
622 | ||
623 | ret = tasdevice_rca_parser(tas_priv, fmw); | |
624 | if (ret) | |
625 | goto out; | |
626 | ||
4e7914eb GK |
627 | tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl, tas_priv); |
628 | ret = snd_ctl_add(codec->card, tas_hda->prof_ctl); | |
5be27f1e SD |
629 | if (ret) { |
630 | dev_err(tas_priv->dev, | |
631 | "Failed to add KControl %s = %d\n", | |
632 | tas2781_prof_ctrl.name, ret); | |
633 | goto out; | |
634 | } | |
635 | ||
636 | for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) { | |
4e7914eb GK |
637 | tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i], |
638 | tas_priv); | |
639 | ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]); | |
5be27f1e SD |
640 | if (ret) { |
641 | dev_err(tas_priv->dev, | |
642 | "Failed to add KControl %s = %d\n", | |
643 | tas2781_snd_controls[i].name, ret); | |
644 | goto out; | |
645 | } | |
646 | } | |
647 | ||
648 | tasdevice_dsp_remove(tas_priv); | |
649 | ||
650 | tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; | |
651 | scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X.bin", | |
652 | codec->core.subsystem_id & 0xffff); | |
653 | ret = tasdevice_dsp_parser(tas_priv); | |
654 | if (ret) { | |
655 | dev_err(tas_priv->dev, "dspfw load %s error\n", | |
656 | tas_priv->coef_binaryname); | |
657 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; | |
658 | goto out; | |
659 | } | |
660 | ||
4e7914eb GK |
661 | tas_hda->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_prog_ctrl, |
662 | tas_priv); | |
663 | ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl); | |
5be27f1e SD |
664 | if (ret) { |
665 | dev_err(tas_priv->dev, | |
666 | "Failed to add KControl %s = %d\n", | |
667 | tas2781_dsp_prog_ctrl.name, ret); | |
668 | goto out; | |
669 | } | |
670 | ||
4e7914eb GK |
671 | tas_hda->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_conf_ctrl, |
672 | tas_priv); | |
673 | ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl); | |
5be27f1e SD |
674 | if (ret) { |
675 | dev_err(tas_priv->dev, | |
676 | "Failed to add KControl %s = %d\n", | |
677 | tas2781_dsp_conf_ctrl.name, ret); | |
678 | goto out; | |
679 | } | |
680 | ||
681 | tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; | |
682 | tasdevice_prmg_load(tas_priv, 0); | |
ec1de5c2 GK |
683 | if (tas_priv->fmw->nr_programs > 0) |
684 | tas_priv->cur_prog = 0; | |
685 | if (tas_priv->fmw->nr_configurations > 0) | |
686 | tas_priv->cur_conf = 0; | |
5be27f1e SD |
687 | |
688 | /* If calibrated data occurs error, dsp will still works with default | |
689 | * calibrated data inside algo. | |
690 | */ | |
76f5f55c | 691 | tasdevice_save_calibration(tas_priv); |
5be27f1e | 692 | |
68f7f3ff | 693 | tasdevice_tuning_switch(tas_hda->priv, 0); |
9fc91a6f | 694 | tas_hda->priv->playback_started = true; |
68f7f3ff | 695 | |
5be27f1e | 696 | out: |
4e7914eb | 697 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e SD |
698 | if (fmw) |
699 | release_firmware(fmw); | |
4e7914eb GK |
700 | pm_runtime_mark_last_busy(tas_hda->dev); |
701 | pm_runtime_put_autosuspend(tas_hda->dev); | |
5be27f1e SD |
702 | } |
703 | ||
704 | static int tas2781_hda_bind(struct device *dev, struct device *master, | |
705 | void *master_data) | |
706 | { | |
4e7914eb | 707 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
1adf9101 ST |
708 | struct hda_component_parent *parent = master_data; |
709 | struct hda_component *comp; | |
5be27f1e SD |
710 | struct hda_codec *codec; |
711 | unsigned int subid; | |
712 | int ret; | |
713 | ||
1adf9101 ST |
714 | comp = hda_component_from_index(parent, tas_hda->priv->index); |
715 | if (!comp) | |
5be27f1e SD |
716 | return -EINVAL; |
717 | ||
1adf9101 | 718 | if (comp->dev) |
5be27f1e SD |
719 | return -EBUSY; |
720 | ||
3b2a8582 | 721 | codec = parent->codec; |
5be27f1e SD |
722 | subid = codec->core.subsystem_id >> 16; |
723 | ||
724 | switch (subid) { | |
725 | case 0x17aa: | |
4e7914eb | 726 | tas_hda->priv->catlog_id = LENOVO; |
5be27f1e SD |
727 | break; |
728 | default: | |
4e7914eb | 729 | tas_hda->priv->catlog_id = OTHERS; |
5be27f1e SD |
730 | break; |
731 | } | |
732 | ||
733 | pm_runtime_get_sync(dev); | |
734 | ||
1adf9101 | 735 | comp->dev = dev; |
5be27f1e | 736 | |
1adf9101 | 737 | strscpy(comp->name, dev_name(dev), sizeof(comp->name)); |
5be27f1e | 738 | |
34a10669 | 739 | ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready); |
17a1eab7 | 740 | if (!ret) |
1adf9101 | 741 | comp->playback_hook = tas2781_hda_playback_hook; |
5be27f1e SD |
742 | |
743 | pm_runtime_mark_last_busy(dev); | |
744 | pm_runtime_put_autosuspend(dev); | |
745 | ||
17a1eab7 | 746 | return ret; |
5be27f1e SD |
747 | } |
748 | ||
749 | static void tas2781_hda_unbind(struct device *dev, | |
750 | struct device *master, void *master_data) | |
751 | { | |
4e7914eb | 752 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
1adf9101 ST |
753 | struct hda_component_parent *parent = master_data; |
754 | struct hda_component *comp; | |
755 | ||
756 | comp = hda_component_from_index(parent, tas_hda->priv->index); | |
757 | if (comp && (comp->dev == dev)) { | |
758 | comp->dev = NULL; | |
759 | memset(comp->name, 0, sizeof(comp->name)); | |
760 | comp->playback_hook = NULL; | |
75a25d31 | 761 | } |
5be27f1e | 762 | |
4e7914eb | 763 | tas2781_hda_remove_controls(tas_hda); |
5be27f1e | 764 | |
4e7914eb GK |
765 | tasdevice_config_info_remove(tas_hda->priv); |
766 | tasdevice_dsp_remove(tas_hda->priv); | |
767 | ||
768 | tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING; | |
5be27f1e SD |
769 | } |
770 | ||
771 | static const struct component_ops tas2781_hda_comp_ops = { | |
772 | .bind = tas2781_hda_bind, | |
773 | .unbind = tas2781_hda_unbind, | |
774 | }; | |
775 | ||
776 | static void tas2781_hda_remove(struct device *dev) | |
777 | { | |
4e7914eb | 778 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5be27f1e | 779 | |
d832b5a0 ST |
780 | component_del(tas_hda->dev, &tas2781_hda_comp_ops); |
781 | ||
4e7914eb GK |
782 | pm_runtime_get_sync(tas_hda->dev); |
783 | pm_runtime_disable(tas_hda->dev); | |
5be27f1e | 784 | |
4e7914eb | 785 | pm_runtime_put_noidle(tas_hda->dev); |
5be27f1e | 786 | |
4e7914eb | 787 | tasdevice_remove(tas_hda->priv); |
5be27f1e SD |
788 | } |
789 | ||
790 | static int tas2781_hda_i2c_probe(struct i2c_client *clt) | |
791 | { | |
4e7914eb | 792 | struct tas2781_hda *tas_hda; |
5be27f1e SD |
793 | const char *device_name; |
794 | int ret; | |
795 | ||
5be27f1e | 796 | |
4e7914eb GK |
797 | tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL); |
798 | if (!tas_hda) | |
5be27f1e SD |
799 | return -ENOMEM; |
800 | ||
4e7914eb GK |
801 | dev_set_drvdata(&clt->dev, tas_hda); |
802 | tas_hda->dev = &clt->dev; | |
803 | ||
804 | tas_hda->priv = tasdevice_kzalloc(clt); | |
805 | if (!tas_hda->priv) | |
806 | return -ENOMEM; | |
e7aa1056 | 807 | |
76f5f55c GK |
808 | if (strstr(dev_name(&clt->dev), "TIAS2781")) { |
809 | device_name = "TIAS2781"; | |
810 | tas_hda->priv->save_calibration = tas2781_save_calibration; | |
811 | tas_hda->priv->apply_calibration = tas2781_apply_calib; | |
c021ca72 | 812 | tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; |
c3ca4458 GK |
813 | } else if (strstr(dev_name(&clt->dev), "INT8866")) { |
814 | device_name = "INT8866"; | |
815 | tas_hda->priv->save_calibration = tas2563_save_calibration; | |
816 | tas_hda->priv->apply_calibration = tas2563_apply_calib; | |
817 | tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR; | |
76f5f55c GK |
818 | } else |
819 | return -ENODEV; | |
820 | ||
c2c0b67d | 821 | tas_hda->priv->irq = clt->irq; |
4e7914eb | 822 | ret = tas2781_read_acpi(tas_hda->priv, device_name); |
5be27f1e | 823 | if (ret) |
4e7914eb | 824 | return dev_err_probe(tas_hda->dev, ret, |
5be27f1e SD |
825 | "Platform not supported\n"); |
826 | ||
4e7914eb | 827 | ret = tasdevice_init(tas_hda->priv); |
5be27f1e SD |
828 | if (ret) |
829 | goto err; | |
830 | ||
4e7914eb GK |
831 | pm_runtime_set_autosuspend_delay(tas_hda->dev, 3000); |
832 | pm_runtime_use_autosuspend(tas_hda->dev); | |
833 | pm_runtime_mark_last_busy(tas_hda->dev); | |
834 | pm_runtime_set_active(tas_hda->dev); | |
4e7914eb | 835 | pm_runtime_enable(tas_hda->dev); |
5be27f1e | 836 | |
be5db758 | 837 | tasdevice_reset(tas_hda->priv); |
315deab2 | 838 | |
4e7914eb | 839 | ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops); |
5be27f1e | 840 | if (ret) { |
4e7914eb GK |
841 | dev_err(tas_hda->dev, "Register component failed: %d\n", ret); |
842 | pm_runtime_disable(tas_hda->dev); | |
5be27f1e SD |
843 | } |
844 | ||
5be27f1e SD |
845 | err: |
846 | if (ret) | |
847 | tas2781_hda_remove(&clt->dev); | |
848 | return ret; | |
849 | } | |
850 | ||
851 | static void tas2781_hda_i2c_remove(struct i2c_client *clt) | |
852 | { | |
853 | tas2781_hda_remove(&clt->dev); | |
854 | } | |
855 | ||
856 | static int tas2781_runtime_suspend(struct device *dev) | |
857 | { | |
4e7914eb | 858 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5be27f1e | 859 | |
4e7914eb | 860 | dev_dbg(tas_hda->dev, "Runtime Suspend\n"); |
5be27f1e | 861 | |
4e7914eb | 862 | mutex_lock(&tas_hda->priv->codec_lock); |
5be27f1e | 863 | |
9fc91a6f GK |
864 | /* The driver powers up the amplifiers at module load time. |
865 | * Stop the playback if it's unused. | |
866 | */ | |
4e7914eb GK |
867 | if (tas_hda->priv->playback_started) { |
868 | tasdevice_tuning_switch(tas_hda->priv, 1); | |
869 | tas_hda->priv->playback_started = false; | |
5be27f1e SD |
870 | } |
871 | ||
4e7914eb | 872 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e SD |
873 | |
874 | return 0; | |
875 | } | |
876 | ||
877 | static int tas2781_runtime_resume(struct device *dev) | |
878 | { | |
4e7914eb | 879 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5be27f1e | 880 | |
4e7914eb | 881 | dev_dbg(tas_hda->dev, "Runtime Resume\n"); |
5be27f1e | 882 | |
4e7914eb | 883 | mutex_lock(&tas_hda->priv->codec_lock); |
5be27f1e | 884 | |
4e7914eb | 885 | tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); |
5be27f1e SD |
886 | |
887 | /* If calibrated data occurs error, dsp will still works with default | |
888 | * calibrated data inside algo. | |
889 | */ | |
76f5f55c | 890 | tasdevice_apply_calibration(tas_hda->priv); |
5be27f1e | 891 | |
4e7914eb | 892 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e | 893 | |
6dad45f4 | 894 | return 0; |
5be27f1e SD |
895 | } |
896 | ||
897 | static int tas2781_system_suspend(struct device *dev) | |
898 | { | |
4e7914eb | 899 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5be27f1e | 900 | |
4e7914eb | 901 | dev_dbg(tas_hda->priv->dev, "System Suspend\n"); |
5be27f1e | 902 | |
c58e6ed5 GK |
903 | mutex_lock(&tas_hda->priv->codec_lock); |
904 | ||
5be27f1e | 905 | /* Shutdown chip before system suspend */ |
9fc91a6f GK |
906 | if (tas_hda->priv->playback_started) |
907 | tasdevice_tuning_switch(tas_hda->priv, 1); | |
5be27f1e | 908 | |
c58e6ed5 GK |
909 | mutex_unlock(&tas_hda->priv->codec_lock); |
910 | ||
5be27f1e SD |
911 | /* |
912 | * Reset GPIO may be shared, so cannot reset here. | |
913 | * However beyond this point, amps may be powered down. | |
914 | */ | |
915 | return 0; | |
916 | } | |
917 | ||
918 | static int tas2781_system_resume(struct device *dev) | |
919 | { | |
4e7914eb | 920 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5f51de7e | 921 | int i; |
5be27f1e | 922 | |
c850c912 | 923 | dev_dbg(tas_hda->priv->dev, "System Resume\n"); |
5be27f1e | 924 | |
4e7914eb | 925 | mutex_lock(&tas_hda->priv->codec_lock); |
5be27f1e | 926 | |
4e7914eb GK |
927 | for (i = 0; i < tas_hda->priv->ndev; i++) { |
928 | tas_hda->priv->tasdevice[i].cur_book = -1; | |
929 | tas_hda->priv->tasdevice[i].cur_prog = -1; | |
930 | tas_hda->priv->tasdevice[i].cur_conf = -1; | |
5be27f1e | 931 | } |
be5db758 | 932 | tasdevice_reset(tas_hda->priv); |
4e7914eb | 933 | tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); |
5be27f1e SD |
934 | |
935 | /* If calibrated data occurs error, dsp will still work with default | |
936 | * calibrated data inside algo. | |
937 | */ | |
76f5f55c | 938 | tasdevice_apply_calibration(tas_hda->priv); |
9fc91a6f GK |
939 | |
940 | if (tas_hda->priv->playback_started) | |
941 | tasdevice_tuning_switch(tas_hda->priv, 0); | |
942 | ||
4e7914eb | 943 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e SD |
944 | |
945 | return 0; | |
946 | } | |
947 | ||
948 | static const struct dev_pm_ops tas2781_hda_pm_ops = { | |
949 | RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL) | |
950 | SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume) | |
951 | }; | |
952 | ||
953 | static const struct i2c_device_id tas2781_hda_i2c_id[] = { | |
bf36793f | 954 | { "tas2781-hda" }, |
5be27f1e SD |
955 | {} |
956 | }; | |
957 | ||
958 | static const struct acpi_device_id tas2781_acpi_hda_match[] = { | |
959 | {"TIAS2781", 0 }, | |
c3ca4458 | 960 | {"INT8866", 0 }, |
5be27f1e SD |
961 | {} |
962 | }; | |
963 | MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match); | |
964 | ||
965 | static struct i2c_driver tas2781_hda_i2c_driver = { | |
966 | .driver = { | |
967 | .name = "tas2781-hda", | |
968 | .acpi_match_table = tas2781_acpi_hda_match, | |
969 | .pm = &tas2781_hda_pm_ops, | |
970 | }, | |
971 | .id_table = tas2781_hda_i2c_id, | |
ed81cb9e | 972 | .probe = tas2781_hda_i2c_probe, |
5be27f1e SD |
973 | .remove = tas2781_hda_i2c_remove, |
974 | }; | |
975 | module_i2c_driver(tas2781_hda_i2c_driver); | |
976 | ||
977 | MODULE_DESCRIPTION("TAS2781 HDA Driver"); | |
978 | MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>"); | |
979 | MODULE_LICENSE("GPL"); | |
980 | MODULE_IMPORT_NS(SND_SOC_TAS2781_FMWLIB); |