Commit | Line | Data |
---|---|---|
5be27f1e SD |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // TAS2781 HDA I2C driver | |
4 | // | |
813e311e | 5 | // Copyright 2023 - 2025 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> | |
4e7035a7 | 19 | #include <linux/pci_ids.h> |
5be27f1e SD |
20 | #include <linux/pm_runtime.h> |
21 | #include <linux/regmap.h> | |
22 | #include <sound/hda_codec.h> | |
23 | #include <sound/soc.h> | |
24 | #include <sound/tas2781.h> | |
9fa6a693 | 25 | #include <sound/tas2781-comlib-i2c.h> |
5be27f1e SD |
26 | #include <sound/tlv.h> |
27 | #include <sound/tas2781-tlv.h> | |
28 | ||
29 | #include "hda_local.h" | |
30 | #include "hda_auto_parser.h" | |
31 | #include "hda_component.h" | |
32 | #include "hda_jack.h" | |
33 | #include "hda_generic.h" | |
813e311e | 34 | #include "tas2781_hda.h" |
5be27f1e | 35 | |
4fe23851 SD |
36 | #define TAS2563_CAL_VAR_NAME_MAX 16 |
37 | #define TAS2563_CAL_ARRAY_SIZE 80 | |
38 | #define TAS2563_CAL_DATA_SIZE 4 | |
39 | #define TAS2563_MAX_CHANNELS 4 | |
40 | #define TAS2563_CAL_CH_SIZE 20 | |
41 | ||
42 | #define TAS2563_CAL_R0_LOW TASDEVICE_REG(0, 0x0f, 0x48) | |
43 | #define TAS2563_CAL_POWER TASDEVICE_REG(0, 0x0d, 0x3c) | |
44 | #define TAS2563_CAL_INVR0 TASDEVICE_REG(0, 0x0f, 0x40) | |
45 | #define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14) | |
46 | #define TAS2563_CAL_R0 TASDEVICE_REG(0, 0x0f, 0x34) | |
c3ca4458 | 47 | |
28a09d9e | 48 | struct tas2781_hda_i2c_priv { |
ae065d0c | 49 | struct snd_kcontrol *snd_ctls[2]; |
4fe23851 | 50 | int (*save_calibration)(struct tas2781_hda *h); |
4e7914eb GK |
51 | }; |
52 | ||
5be27f1e SD |
53 | static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) |
54 | { | |
55 | struct tasdevice_priv *tas_priv = data; | |
56 | struct acpi_resource_i2c_serialbus *sb; | |
57 | ||
58 | if (i2c_acpi_get_i2c_resource(ares, &sb)) { | |
59 | if (tas_priv->ndev < TASDEVICE_MAX_CHANNELS && | |
c021ca72 | 60 | sb->slave_address != tas_priv->global_addr) { |
5be27f1e SD |
61 | tas_priv->tasdevice[tas_priv->ndev].dev_addr = |
62 | (unsigned int)sb->slave_address; | |
63 | tas_priv->ndev++; | |
64 | } | |
65 | } | |
66 | return 1; | |
67 | } | |
68 | ||
4e7035a7 BX |
69 | static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false }; |
70 | ||
71 | static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = { | |
72 | { "speakerid-gpios", &speakerid_gpios, 1 }, | |
73 | { } | |
74 | }; | |
75 | ||
5be27f1e SD |
76 | static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) |
77 | { | |
78 | struct acpi_device *adev; | |
4e7035a7 | 79 | struct device *physdev; |
5be27f1e | 80 | LIST_HEAD(resources); |
4e7035a7 BX |
81 | const char *sub; |
82 | uint32_t subid; | |
5be27f1e SD |
83 | int ret; |
84 | ||
85 | adev = acpi_dev_get_first_match_dev(hid, NULL, -1); | |
86 | if (!adev) { | |
87 | dev_err(p->dev, | |
88 | "Failed to find an ACPI device for %s\n", hid); | |
89 | return -ENODEV; | |
90 | } | |
91 | ||
4e7035a7 | 92 | physdev = get_device(acpi_get_first_physical_node(adev)); |
5be27f1e | 93 | ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p); |
4e7035a7 BX |
94 | if (ret < 0) { |
95 | dev_err(p->dev, "Failed to get ACPI resource.\n"); | |
96 | goto err; | |
97 | } | |
98 | sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); | |
99 | if (IS_ERR(sub)) { | |
6a451e2c BX |
100 | /* No subsys id in older tas2563 projects. */ |
101 | if (!strncmp(hid, "INT8866", sizeof("INT8866"))) | |
102 | goto end_2563; | |
4e7035a7 | 103 | dev_err(p->dev, "Failed to get SUBSYS ID.\n"); |
a0cd2b26 | 104 | ret = PTR_ERR(sub); |
5be27f1e | 105 | goto err; |
4e7035a7 BX |
106 | } |
107 | /* Speaker id was needed for ASUS projects. */ | |
108 | ret = kstrtou32(sub, 16, &subid); | |
109 | if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) { | |
110 | ret = devm_acpi_dev_add_driver_gpios(p->dev, | |
111 | tas2781_speaker_id_gpios); | |
112 | if (ret < 0) | |
113 | dev_err(p->dev, "Failed to add driver gpio %d.\n", | |
114 | ret); | |
115 | p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN); | |
116 | if (IS_ERR(p->speaker_id)) { | |
117 | dev_err(p->dev, "Failed to get Speaker id.\n"); | |
118 | ret = PTR_ERR(p->speaker_id); | |
119 | goto err; | |
120 | } | |
121 | } else { | |
122 | p->speaker_id = NULL; | |
123 | } | |
5be27f1e | 124 | |
6a451e2c | 125 | end_2563: |
5be27f1e SD |
126 | acpi_dev_free_resource_list(&resources); |
127 | strscpy(p->dev_name, hid, sizeof(p->dev_name)); | |
4e7035a7 | 128 | put_device(physdev); |
5be27f1e SD |
129 | acpi_dev_put(adev); |
130 | ||
5be27f1e SD |
131 | return 0; |
132 | ||
133 | err: | |
134 | dev_err(p->dev, "read acpi error, ret: %d\n", ret); | |
4e7035a7 | 135 | put_device(physdev); |
1c80cc05 | 136 | acpi_dev_put(adev); |
5be27f1e SD |
137 | |
138 | return ret; | |
139 | } | |
140 | ||
141 | static void tas2781_hda_playback_hook(struct device *dev, int action) | |
142 | { | |
4e7914eb | 143 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5be27f1e | 144 | |
4e7914eb | 145 | dev_dbg(tas_hda->dev, "%s: action = %d\n", __func__, action); |
5be27f1e SD |
146 | switch (action) { |
147 | case HDA_GEN_PCM_ACT_OPEN: | |
148 | pm_runtime_get_sync(dev); | |
4e7914eb GK |
149 | mutex_lock(&tas_hda->priv->codec_lock); |
150 | tasdevice_tuning_switch(tas_hda->priv, 0); | |
9fc91a6f | 151 | tas_hda->priv->playback_started = true; |
4e7914eb | 152 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e SD |
153 | break; |
154 | case HDA_GEN_PCM_ACT_CLOSE: | |
4e7914eb GK |
155 | mutex_lock(&tas_hda->priv->codec_lock); |
156 | tasdevice_tuning_switch(tas_hda->priv, 1); | |
9fc91a6f | 157 | tas_hda->priv->playback_started = false; |
4e7914eb | 158 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e SD |
159 | |
160 | pm_runtime_mark_last_busy(dev); | |
161 | pm_runtime_put_autosuspend(dev); | |
162 | break; | |
163 | default: | |
5be27f1e SD |
164 | break; |
165 | } | |
166 | } | |
167 | ||
5be27f1e SD |
168 | static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol, |
169 | struct snd_ctl_elem_value *ucontrol) | |
170 | { | |
171 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
172 | struct soc_mixer_control *mc = | |
173 | (struct soc_mixer_control *)kcontrol->private_value; | |
15bc3066 | 174 | int ret; |
5be27f1e | 175 | |
15bc3066 GK |
176 | mutex_lock(&tas_priv->codec_lock); |
177 | ||
178 | ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc); | |
179 | ||
26c04a8a GK |
180 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n", |
181 | __func__, kcontrol->id.name, ucontrol->value.integer.value[0]); | |
182 | ||
15bc3066 GK |
183 | mutex_unlock(&tas_priv->codec_lock); |
184 | ||
185 | return ret; | |
5be27f1e SD |
186 | } |
187 | ||
5be27f1e SD |
188 | static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol, |
189 | struct snd_ctl_elem_value *ucontrol) | |
190 | { | |
191 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
192 | struct soc_mixer_control *mc = | |
193 | (struct soc_mixer_control *)kcontrol->private_value; | |
15bc3066 GK |
194 | int ret; |
195 | ||
196 | mutex_lock(&tas_priv->codec_lock); | |
5be27f1e | 197 | |
26c04a8a GK |
198 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n", |
199 | __func__, kcontrol->id.name, ucontrol->value.integer.value[0]); | |
200 | ||
5be27f1e | 201 | /* The check of the given value is in tasdevice_amp_putvol. */ |
15bc3066 GK |
202 | ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc); |
203 | ||
204 | mutex_unlock(&tas_priv->codec_lock); | |
205 | ||
206 | return ret; | |
5be27f1e SD |
207 | } |
208 | ||
209 | static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol, | |
210 | struct snd_ctl_elem_value *ucontrol) | |
211 | { | |
212 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
213 | ||
15bc3066 GK |
214 | mutex_lock(&tas_priv->codec_lock); |
215 | ||
5be27f1e | 216 | ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status; |
26c04a8a GK |
217 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", |
218 | __func__, kcontrol->id.name, tas_priv->force_fwload_status); | |
5be27f1e | 219 | |
15bc3066 GK |
220 | mutex_unlock(&tas_priv->codec_lock); |
221 | ||
5be27f1e SD |
222 | return 0; |
223 | } | |
224 | ||
225 | static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, | |
226 | struct snd_ctl_elem_value *ucontrol) | |
227 | { | |
228 | struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol); | |
229 | bool change, val = (bool)ucontrol->value.integer.value[0]; | |
230 | ||
15bc3066 GK |
231 | mutex_lock(&tas_priv->codec_lock); |
232 | ||
26c04a8a GK |
233 | dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", |
234 | __func__, kcontrol->id.name, | |
235 | tas_priv->force_fwload_status, val); | |
236 | ||
5be27f1e SD |
237 | if (tas_priv->force_fwload_status == val) |
238 | change = false; | |
239 | else { | |
240 | change = true; | |
241 | tas_priv->force_fwload_status = val; | |
242 | } | |
5be27f1e | 243 | |
15bc3066 GK |
244 | mutex_unlock(&tas_priv->codec_lock); |
245 | ||
5be27f1e SD |
246 | return change; |
247 | } | |
248 | ||
249 | static const struct snd_kcontrol_new tas2781_snd_controls[] = { | |
250 | ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL, | |
251 | 1, 0, 20, 0, tas2781_amp_getvol, | |
252 | tas2781_amp_putvol, amp_vol_tlv), | |
5be27f1e SD |
253 | ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, |
254 | tas2781_force_fwload_get, tas2781_force_fwload_put), | |
255 | }; | |
256 | ||
257 | static const struct snd_kcontrol_new tas2781_prof_ctrl = { | |
258 | .name = "Speaker Profile Id", | |
259 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | |
260 | .info = tasdevice_info_profile, | |
261 | .get = tasdevice_get_profile_id, | |
262 | .put = tasdevice_set_profile_id, | |
263 | }; | |
264 | ||
265 | static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl = { | |
266 | .name = "Speaker Program Id", | |
267 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | |
268 | .info = tasdevice_info_programs, | |
269 | .get = tasdevice_program_get, | |
270 | .put = tasdevice_program_put, | |
271 | }; | |
272 | ||
273 | static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl = { | |
274 | .name = "Speaker Config Id", | |
275 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | |
276 | .info = tasdevice_info_config, | |
277 | .get = tasdevice_config_get, | |
278 | .put = tasdevice_config_put, | |
279 | }; | |
280 | ||
4fe23851 | 281 | static int tas2563_save_calibration(struct tas2781_hda *h) |
c3ca4458 | 282 | { |
4fe23851 SD |
283 | efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO]; |
284 | char *vars[TASDEV_CALIB_N] = { | |
285 | "R0_%d", "InvR0_%d", "R0_Low_%d", "Power_%d", "TLim_%d" | |
c3ca4458 | 286 | }; |
4fe23851 | 287 | efi_char16_t efi_name[TAS2563_CAL_VAR_NAME_MAX]; |
c3ca4458 | 288 | unsigned long max_size = TAS2563_CAL_DATA_SIZE; |
4fe23851 SD |
289 | unsigned char var8[TAS2563_CAL_VAR_NAME_MAX]; |
290 | struct tasdevice_priv *p = h->hda_priv; | |
291 | struct calidata *cd = &p->cali_data; | |
292 | struct cali_reg *r = &cd->cali_reg_array; | |
c3ca4458 | 293 | unsigned int offset = 0; |
4fe23851 | 294 | unsigned char *data; |
c3ca4458 GK |
295 | efi_status_t status; |
296 | unsigned int attr; | |
4fe23851 SD |
297 | int ret, i, j, k; |
298 | ||
299 | cd->cali_dat_sz_per_dev = TAS2563_CAL_DATA_SIZE * TASDEV_CALIB_N; | |
c3ca4458 | 300 | |
4fe23851 SD |
301 | /* extra byte for each device is the device number */ |
302 | cd->total_sz = (cd->cali_dat_sz_per_dev + 1) * p->ndev; | |
303 | data = cd->data = devm_kzalloc(p->dev, cd->total_sz, | |
304 | GFP_KERNEL); | |
305 | if (!data) | |
c3ca4458 GK |
306 | return -ENOMEM; |
307 | ||
4fe23851 SD |
308 | for (i = 0; i < p->ndev; ++i) { |
309 | data[offset] = i; | |
310 | offset++; | |
311 | for (j = 0; j < TASDEV_CALIB_N; ++j) { | |
312 | ret = snprintf(var8, sizeof(var8), vars[j], i); | |
313 | ||
314 | if (ret < 0 || ret >= sizeof(var8) - 1) { | |
315 | dev_err(p->dev, "%s: Read %s failed\n", | |
316 | __func__, var8); | |
317 | return -EINVAL; | |
318 | } | |
319 | /* | |
320 | * Our variable names are ASCII by construction, but | |
321 | * EFI names are wide chars. Convert and zero-pad. | |
322 | */ | |
323 | memset(efi_name, 0, sizeof(efi_name)); | |
324 | for (k = 0; k < sizeof(var8) && var8[k]; k++) | |
325 | efi_name[k] = var8[k]; | |
326 | status = efi.get_variable(efi_name, | |
c3ca4458 | 327 | &efi_guid, &attr, &max_size, |
4fe23851 | 328 | &data[offset]); |
c3ca4458 GK |
329 | if (status != EFI_SUCCESS || |
330 | max_size != TAS2563_CAL_DATA_SIZE) { | |
4fe23851 SD |
331 | dev_warn(p->dev, |
332 | "Dev %d: Caldat[%d] read failed %ld\n", | |
333 | i, j, status); | |
c3ca4458 GK |
334 | return -EINVAL; |
335 | } | |
336 | offset += TAS2563_CAL_DATA_SIZE; | |
337 | } | |
338 | } | |
339 | ||
4fe23851 SD |
340 | if (cd->total_sz != offset) { |
341 | dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) dismatch\n", | |
342 | __func__, cd->total_sz, offset); | |
33071422 | 343 | return -EINVAL; |
4fe23851 | 344 | } |
5be27f1e | 345 | |
4fe23851 SD |
346 | r->r0_reg = TAS2563_CAL_R0; |
347 | r->invr0_reg = TAS2563_CAL_INVR0; | |
348 | r->r0_low_reg = TAS2563_CAL_R0_LOW; | |
349 | r->pow_reg = TAS2563_CAL_POWER; | |
350 | r->tlimit_reg = TAS2563_CAL_TLIM; | |
cb161c33 | 351 | |
4fe23851 SD |
352 | /* |
353 | * TAS2781_FMWLIB supports two solutions of calibrated data. One is | |
354 | * from the driver itself: driver reads the calibrated files directly | |
355 | * during probe; The other from user space: during init of audio hal, | |
356 | * the audio hal will pass the calibrated data via kcontrol interface. | |
357 | * Driver will store this data in "struct calidata" for use. For hda | |
358 | * device, calibrated data are usunally saved into UEFI. So Hda side | |
359 | * codec driver use the mixture of these two solutions, driver reads | |
360 | * the data from UEFI, then store this data in "struct calidata" for | |
361 | * use. | |
362 | */ | |
363 | p->is_user_space_calidata = true; | |
5be27f1e SD |
364 | |
365 | return 0; | |
366 | } | |
367 | ||
4e7914eb GK |
368 | static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) |
369 | { | |
28a09d9e | 370 | struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; |
4e7914eb GK |
371 | struct hda_codec *codec = tas_hda->priv->codec; |
372 | ||
9d67a400 TI |
373 | snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl); |
374 | snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl); | |
4e7914eb | 375 | |
28a09d9e SD |
376 | for (int i = ARRAY_SIZE(hda_priv->snd_ctls) - 1; i >= 0; i--) |
377 | snd_ctl_remove(codec->card, hda_priv->snd_ctls[i]); | |
4e7914eb | 378 | |
9d67a400 | 379 | snd_ctl_remove(codec->card, tas_hda->prof_ctl); |
4e7914eb GK |
380 | } |
381 | ||
5be27f1e SD |
382 | static void tasdev_fw_ready(const struct firmware *fmw, void *context) |
383 | { | |
384 | struct tasdevice_priv *tas_priv = context; | |
4e7914eb | 385 | struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); |
28a09d9e | 386 | struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; |
5be27f1e | 387 | struct hda_codec *codec = tas_priv->codec; |
4e7035a7 | 388 | int i, ret, spk_id; |
5be27f1e SD |
389 | |
390 | pm_runtime_get_sync(tas_priv->dev); | |
391 | mutex_lock(&tas_priv->codec_lock); | |
392 | ||
393 | ret = tasdevice_rca_parser(tas_priv, fmw); | |
394 | if (ret) | |
395 | goto out; | |
396 | ||
4e7914eb GK |
397 | tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl, tas_priv); |
398 | ret = snd_ctl_add(codec->card, tas_hda->prof_ctl); | |
5be27f1e SD |
399 | if (ret) { |
400 | dev_err(tas_priv->dev, | |
401 | "Failed to add KControl %s = %d\n", | |
402 | tas2781_prof_ctrl.name, ret); | |
403 | goto out; | |
404 | } | |
405 | ||
406 | for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) { | |
28a09d9e | 407 | hda_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i], |
4e7914eb | 408 | tas_priv); |
28a09d9e | 409 | ret = snd_ctl_add(codec->card, hda_priv->snd_ctls[i]); |
5be27f1e SD |
410 | if (ret) { |
411 | dev_err(tas_priv->dev, | |
412 | "Failed to add KControl %s = %d\n", | |
413 | tas2781_snd_controls[i].name, ret); | |
414 | goto out; | |
415 | } | |
416 | } | |
417 | ||
418 | tasdevice_dsp_remove(tas_priv); | |
419 | ||
420 | tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; | |
4e7035a7 BX |
421 | if (tas_priv->speaker_id != NULL) { |
422 | // Speaker id need to be checked for ASUS only. | |
423 | spk_id = gpiod_get_value(tas_priv->speaker_id); | |
424 | if (spk_id < 0) { | |
425 | // Speaker id is not valid, use default. | |
426 | dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id); | |
427 | spk_id = 0; | |
428 | } | |
429 | snprintf(tas_priv->coef_binaryname, | |
430 | sizeof(tas_priv->coef_binaryname), | |
431 | "TAS2XXX%04X%d.bin", | |
432 | lower_16_bits(codec->core.subsystem_id), | |
433 | spk_id); | |
434 | } else { | |
435 | snprintf(tas_priv->coef_binaryname, | |
436 | sizeof(tas_priv->coef_binaryname), | |
437 | "TAS2XXX%04X.bin", | |
438 | lower_16_bits(codec->core.subsystem_id)); | |
439 | } | |
5be27f1e SD |
440 | ret = tasdevice_dsp_parser(tas_priv); |
441 | if (ret) { | |
442 | dev_err(tas_priv->dev, "dspfw load %s error\n", | |
443 | tas_priv->coef_binaryname); | |
444 | tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; | |
445 | goto out; | |
446 | } | |
447 | ||
4e7914eb GK |
448 | tas_hda->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_prog_ctrl, |
449 | tas_priv); | |
450 | ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl); | |
5be27f1e SD |
451 | if (ret) { |
452 | dev_err(tas_priv->dev, | |
453 | "Failed to add KControl %s = %d\n", | |
454 | tas2781_dsp_prog_ctrl.name, ret); | |
455 | goto out; | |
456 | } | |
457 | ||
4e7914eb GK |
458 | tas_hda->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_conf_ctrl, |
459 | tas_priv); | |
460 | ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl); | |
5be27f1e SD |
461 | if (ret) { |
462 | dev_err(tas_priv->dev, | |
463 | "Failed to add KControl %s = %d\n", | |
464 | tas2781_dsp_conf_ctrl.name, ret); | |
465 | goto out; | |
466 | } | |
467 | ||
468 | tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; | |
469 | tasdevice_prmg_load(tas_priv, 0); | |
ec1de5c2 GK |
470 | if (tas_priv->fmw->nr_programs > 0) |
471 | tas_priv->cur_prog = 0; | |
472 | if (tas_priv->fmw->nr_configurations > 0) | |
473 | tas_priv->cur_conf = 0; | |
5be27f1e SD |
474 | |
475 | /* If calibrated data occurs error, dsp will still works with default | |
476 | * calibrated data inside algo. | |
477 | */ | |
4fe23851 | 478 | hda_priv->save_calibration(tas_hda); |
5be27f1e | 479 | |
68f7f3ff | 480 | tasdevice_tuning_switch(tas_hda->priv, 0); |
9fc91a6f | 481 | tas_hda->priv->playback_started = true; |
68f7f3ff | 482 | |
5be27f1e | 483 | out: |
4e7914eb | 484 | mutex_unlock(&tas_hda->priv->codec_lock); |
3a949fc0 | 485 | release_firmware(fmw); |
4e7914eb GK |
486 | pm_runtime_mark_last_busy(tas_hda->dev); |
487 | pm_runtime_put_autosuspend(tas_hda->dev); | |
5be27f1e SD |
488 | } |
489 | ||
490 | static int tas2781_hda_bind(struct device *dev, struct device *master, | |
491 | void *master_data) | |
492 | { | |
4e7914eb | 493 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
1adf9101 ST |
494 | struct hda_component_parent *parent = master_data; |
495 | struct hda_component *comp; | |
5be27f1e SD |
496 | struct hda_codec *codec; |
497 | unsigned int subid; | |
498 | int ret; | |
499 | ||
1adf9101 ST |
500 | comp = hda_component_from_index(parent, tas_hda->priv->index); |
501 | if (!comp) | |
5be27f1e SD |
502 | return -EINVAL; |
503 | ||
1adf9101 | 504 | if (comp->dev) |
5be27f1e SD |
505 | return -EBUSY; |
506 | ||
3b2a8582 | 507 | codec = parent->codec; |
5be27f1e SD |
508 | subid = codec->core.subsystem_id >> 16; |
509 | ||
510 | switch (subid) { | |
4fe23851 SD |
511 | case 0x1028: |
512 | tas_hda->catlog_id = DELL; | |
5be27f1e SD |
513 | break; |
514 | default: | |
4fe23851 | 515 | tas_hda->catlog_id = LENOVO; |
5be27f1e SD |
516 | break; |
517 | } | |
518 | ||
519 | pm_runtime_get_sync(dev); | |
520 | ||
1adf9101 | 521 | comp->dev = dev; |
5be27f1e | 522 | |
1adf9101 | 523 | strscpy(comp->name, dev_name(dev), sizeof(comp->name)); |
5be27f1e | 524 | |
34a10669 | 525 | ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready); |
17a1eab7 | 526 | if (!ret) |
1adf9101 | 527 | comp->playback_hook = tas2781_hda_playback_hook; |
5be27f1e SD |
528 | |
529 | pm_runtime_mark_last_busy(dev); | |
530 | pm_runtime_put_autosuspend(dev); | |
531 | ||
17a1eab7 | 532 | return ret; |
5be27f1e SD |
533 | } |
534 | ||
535 | static void tas2781_hda_unbind(struct device *dev, | |
536 | struct device *master, void *master_data) | |
537 | { | |
4e7914eb | 538 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
1adf9101 ST |
539 | struct hda_component_parent *parent = master_data; |
540 | struct hda_component *comp; | |
541 | ||
542 | comp = hda_component_from_index(parent, tas_hda->priv->index); | |
543 | if (comp && (comp->dev == dev)) { | |
544 | comp->dev = NULL; | |
545 | memset(comp->name, 0, sizeof(comp->name)); | |
546 | comp->playback_hook = NULL; | |
75a25d31 | 547 | } |
5be27f1e | 548 | |
4e7914eb | 549 | tas2781_hda_remove_controls(tas_hda); |
5be27f1e | 550 | |
4e7914eb GK |
551 | tasdevice_config_info_remove(tas_hda->priv); |
552 | tasdevice_dsp_remove(tas_hda->priv); | |
553 | ||
554 | tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING; | |
5be27f1e SD |
555 | } |
556 | ||
557 | static const struct component_ops tas2781_hda_comp_ops = { | |
558 | .bind = tas2781_hda_bind, | |
559 | .unbind = tas2781_hda_unbind, | |
560 | }; | |
561 | ||
5be27f1e SD |
562 | static int tas2781_hda_i2c_probe(struct i2c_client *clt) |
563 | { | |
28a09d9e | 564 | struct tas2781_hda_i2c_priv *hda_priv; |
4e7914eb | 565 | struct tas2781_hda *tas_hda; |
5be27f1e SD |
566 | const char *device_name; |
567 | int ret; | |
568 | ||
4e7914eb GK |
569 | tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL); |
570 | if (!tas_hda) | |
5be27f1e SD |
571 | return -ENOMEM; |
572 | ||
28a09d9e SD |
573 | hda_priv = devm_kzalloc(&clt->dev, sizeof(*hda_priv), GFP_KERNEL); |
574 | if (!hda_priv) | |
575 | return -ENOMEM; | |
576 | ||
577 | tas_hda->hda_priv = hda_priv; | |
578 | ||
4e7914eb GK |
579 | dev_set_drvdata(&clt->dev, tas_hda); |
580 | tas_hda->dev = &clt->dev; | |
581 | ||
582 | tas_hda->priv = tasdevice_kzalloc(clt); | |
583 | if (!tas_hda->priv) | |
584 | return -ENOMEM; | |
e7aa1056 | 585 | |
76f5f55c GK |
586 | if (strstr(dev_name(&clt->dev), "TIAS2781")) { |
587 | device_name = "TIAS2781"; | |
4fe23851 | 588 | hda_priv->save_calibration = tas2781_save_calibration; |
c021ca72 | 589 | tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; |
c3ca4458 GK |
590 | } else if (strstr(dev_name(&clt->dev), "INT8866")) { |
591 | device_name = "INT8866"; | |
4fe23851 | 592 | hda_priv->save_calibration = tas2563_save_calibration; |
c3ca4458 | 593 | tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR; |
76f5f55c GK |
594 | } else |
595 | return -ENODEV; | |
596 | ||
c2c0b67d | 597 | tas_hda->priv->irq = clt->irq; |
4e7914eb | 598 | ret = tas2781_read_acpi(tas_hda->priv, device_name); |
5be27f1e | 599 | if (ret) |
4e7914eb | 600 | return dev_err_probe(tas_hda->dev, ret, |
5be27f1e SD |
601 | "Platform not supported\n"); |
602 | ||
4e7914eb | 603 | ret = tasdevice_init(tas_hda->priv); |
5be27f1e SD |
604 | if (ret) |
605 | goto err; | |
606 | ||
4e7914eb GK |
607 | pm_runtime_set_autosuspend_delay(tas_hda->dev, 3000); |
608 | pm_runtime_use_autosuspend(tas_hda->dev); | |
609 | pm_runtime_mark_last_busy(tas_hda->dev); | |
610 | pm_runtime_set_active(tas_hda->dev); | |
4e7914eb | 611 | pm_runtime_enable(tas_hda->dev); |
5be27f1e | 612 | |
be5db758 | 613 | tasdevice_reset(tas_hda->priv); |
315deab2 | 614 | |
4e7914eb | 615 | ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops); |
5be27f1e | 616 | if (ret) { |
4e7914eb GK |
617 | dev_err(tas_hda->dev, "Register component failed: %d\n", ret); |
618 | pm_runtime_disable(tas_hda->dev); | |
5be27f1e SD |
619 | } |
620 | ||
5be27f1e SD |
621 | err: |
622 | if (ret) | |
28a09d9e | 623 | tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops); |
5be27f1e SD |
624 | return ret; |
625 | } | |
626 | ||
627 | static void tas2781_hda_i2c_remove(struct i2c_client *clt) | |
628 | { | |
28a09d9e | 629 | tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops); |
5be27f1e SD |
630 | } |
631 | ||
632 | static int tas2781_runtime_suspend(struct device *dev) | |
633 | { | |
4e7914eb | 634 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5be27f1e | 635 | |
4e7914eb | 636 | dev_dbg(tas_hda->dev, "Runtime Suspend\n"); |
5be27f1e | 637 | |
4e7914eb | 638 | mutex_lock(&tas_hda->priv->codec_lock); |
5be27f1e | 639 | |
9fc91a6f GK |
640 | /* The driver powers up the amplifiers at module load time. |
641 | * Stop the playback if it's unused. | |
642 | */ | |
4e7914eb GK |
643 | if (tas_hda->priv->playback_started) { |
644 | tasdevice_tuning_switch(tas_hda->priv, 1); | |
645 | tas_hda->priv->playback_started = false; | |
5be27f1e SD |
646 | } |
647 | ||
4e7914eb | 648 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e SD |
649 | |
650 | return 0; | |
651 | } | |
652 | ||
653 | static int tas2781_runtime_resume(struct device *dev) | |
654 | { | |
4e7914eb | 655 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5be27f1e | 656 | |
4e7914eb | 657 | dev_dbg(tas_hda->dev, "Runtime Resume\n"); |
5be27f1e | 658 | |
4e7914eb | 659 | mutex_lock(&tas_hda->priv->codec_lock); |
5be27f1e | 660 | |
4e7914eb | 661 | tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); |
5be27f1e | 662 | |
4e7914eb | 663 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e | 664 | |
6dad45f4 | 665 | return 0; |
5be27f1e SD |
666 | } |
667 | ||
668 | static int tas2781_system_suspend(struct device *dev) | |
669 | { | |
4e7914eb | 670 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5be27f1e | 671 | |
4e7914eb | 672 | dev_dbg(tas_hda->priv->dev, "System Suspend\n"); |
5be27f1e | 673 | |
c58e6ed5 GK |
674 | mutex_lock(&tas_hda->priv->codec_lock); |
675 | ||
5be27f1e | 676 | /* Shutdown chip before system suspend */ |
9fc91a6f GK |
677 | if (tas_hda->priv->playback_started) |
678 | tasdevice_tuning_switch(tas_hda->priv, 1); | |
5be27f1e | 679 | |
c58e6ed5 GK |
680 | mutex_unlock(&tas_hda->priv->codec_lock); |
681 | ||
5be27f1e SD |
682 | /* |
683 | * Reset GPIO may be shared, so cannot reset here. | |
684 | * However beyond this point, amps may be powered down. | |
685 | */ | |
686 | return 0; | |
687 | } | |
688 | ||
689 | static int tas2781_system_resume(struct device *dev) | |
690 | { | |
4e7914eb | 691 | struct tas2781_hda *tas_hda = dev_get_drvdata(dev); |
5f51de7e | 692 | int i; |
5be27f1e | 693 | |
c850c912 | 694 | dev_dbg(tas_hda->priv->dev, "System Resume\n"); |
5be27f1e | 695 | |
4e7914eb | 696 | mutex_lock(&tas_hda->priv->codec_lock); |
5be27f1e | 697 | |
4e7914eb GK |
698 | for (i = 0; i < tas_hda->priv->ndev; i++) { |
699 | tas_hda->priv->tasdevice[i].cur_book = -1; | |
700 | tas_hda->priv->tasdevice[i].cur_prog = -1; | |
701 | tas_hda->priv->tasdevice[i].cur_conf = -1; | |
5be27f1e | 702 | } |
be5db758 | 703 | tasdevice_reset(tas_hda->priv); |
4e7914eb | 704 | tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog); |
5be27f1e | 705 | |
9fc91a6f GK |
706 | if (tas_hda->priv->playback_started) |
707 | tasdevice_tuning_switch(tas_hda->priv, 0); | |
708 | ||
4e7914eb | 709 | mutex_unlock(&tas_hda->priv->codec_lock); |
5be27f1e SD |
710 | |
711 | return 0; | |
712 | } | |
713 | ||
714 | static const struct dev_pm_ops tas2781_hda_pm_ops = { | |
715 | RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL) | |
716 | SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume) | |
717 | }; | |
718 | ||
719 | static const struct i2c_device_id tas2781_hda_i2c_id[] = { | |
bf36793f | 720 | { "tas2781-hda" }, |
5be27f1e SD |
721 | {} |
722 | }; | |
723 | ||
724 | static const struct acpi_device_id tas2781_acpi_hda_match[] = { | |
725 | {"TIAS2781", 0 }, | |
c3ca4458 | 726 | {"INT8866", 0 }, |
5be27f1e SD |
727 | {} |
728 | }; | |
729 | MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match); | |
730 | ||
731 | static struct i2c_driver tas2781_hda_i2c_driver = { | |
732 | .driver = { | |
733 | .name = "tas2781-hda", | |
734 | .acpi_match_table = tas2781_acpi_hda_match, | |
735 | .pm = &tas2781_hda_pm_ops, | |
736 | }, | |
737 | .id_table = tas2781_hda_i2c_id, | |
ed81cb9e | 738 | .probe = tas2781_hda_i2c_probe, |
5be27f1e SD |
739 | .remove = tas2781_hda_i2c_remove, |
740 | }; | |
741 | module_i2c_driver(tas2781_hda_i2c_driver); | |
742 | ||
743 | MODULE_DESCRIPTION("TAS2781 HDA Driver"); | |
744 | MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>"); | |
745 | MODULE_LICENSE("GPL"); | |
cdd30ebb | 746 | MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB"); |
28a09d9e | 747 | MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781"); |