diff options
Diffstat (limited to 'sound/pci/hda/hda_codec.c')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 731 |
1 files changed, 142 insertions, 589 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5e755eb6f19a..db86b446743c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/mutex.h> | 26 | #include <linux/mutex.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/async.h> | 28 | #include <linux/async.h> |
29 | #include <linux/pm.h> | ||
30 | #include <linux/pm_runtime.h> | ||
29 | #include <sound/core.h> | 31 | #include <sound/core.h> |
30 | #include "hda_codec.h" | 32 | #include "hda_codec.h" |
31 | #include <sound/asoundef.h> | 33 | #include <sound/asoundef.h> |
@@ -40,92 +42,13 @@ | |||
40 | #define CREATE_TRACE_POINTS | 42 | #define CREATE_TRACE_POINTS |
41 | #include "hda_trace.h" | 43 | #include "hda_trace.h" |
42 | 44 | ||
43 | /* | ||
44 | * vendor / preset table | ||
45 | */ | ||
46 | |||
47 | struct hda_vendor_id { | ||
48 | unsigned int id; | ||
49 | const char *name; | ||
50 | }; | ||
51 | |||
52 | /* codec vendor labels */ | ||
53 | static struct hda_vendor_id hda_vendor_ids[] = { | ||
54 | { 0x1002, "ATI" }, | ||
55 | { 0x1013, "Cirrus Logic" }, | ||
56 | { 0x1057, "Motorola" }, | ||
57 | { 0x1095, "Silicon Image" }, | ||
58 | { 0x10de, "Nvidia" }, | ||
59 | { 0x10ec, "Realtek" }, | ||
60 | { 0x1102, "Creative" }, | ||
61 | { 0x1106, "VIA" }, | ||
62 | { 0x111d, "IDT" }, | ||
63 | { 0x11c1, "LSI" }, | ||
64 | { 0x11d4, "Analog Devices" }, | ||
65 | { 0x13f6, "C-Media" }, | ||
66 | { 0x14f1, "Conexant" }, | ||
67 | { 0x17e8, "Chrontel" }, | ||
68 | { 0x1854, "LG" }, | ||
69 | { 0x1aec, "Wolfson Microelectronics" }, | ||
70 | { 0x1af4, "QEMU" }, | ||
71 | { 0x434d, "C-Media" }, | ||
72 | { 0x8086, "Intel" }, | ||
73 | { 0x8384, "SigmaTel" }, | ||
74 | {} /* terminator */ | ||
75 | }; | ||
76 | |||
77 | static DEFINE_MUTEX(preset_mutex); | ||
78 | static LIST_HEAD(hda_preset_tables); | ||
79 | |||
80 | /** | ||
81 | * snd_hda_add_codec_preset - Add a codec preset to the chain | ||
82 | * @preset: codec preset table to add | ||
83 | */ | ||
84 | int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) | ||
85 | { | ||
86 | mutex_lock(&preset_mutex); | ||
87 | list_add_tail(&preset->list, &hda_preset_tables); | ||
88 | mutex_unlock(&preset_mutex); | ||
89 | return 0; | ||
90 | } | ||
91 | EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset); | ||
92 | |||
93 | /** | ||
94 | * snd_hda_delete_codec_preset - Delete a codec preset from the chain | ||
95 | * @preset: codec preset table to delete | ||
96 | */ | ||
97 | int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) | ||
98 | { | ||
99 | mutex_lock(&preset_mutex); | ||
100 | list_del(&preset->list); | ||
101 | mutex_unlock(&preset_mutex); | ||
102 | return 0; | ||
103 | } | ||
104 | EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset); | ||
105 | |||
106 | #ifdef CONFIG_PM | 45 | #ifdef CONFIG_PM |
107 | #define codec_in_pm(codec) ((codec)->in_pm) | 46 | #define codec_in_pm(codec) atomic_read(&(codec)->in_pm) |
108 | static void hda_power_work(struct work_struct *work); | 47 | #define hda_codec_is_power_on(codec) \ |
109 | static void hda_keep_power_on(struct hda_codec *codec); | 48 | (!pm_runtime_suspended(hda_codec_dev(codec))) |
110 | #define hda_codec_is_power_on(codec) ((codec)->power_on) | ||
111 | |||
112 | static void hda_call_pm_notify(struct hda_codec *codec, bool power_up) | ||
113 | { | ||
114 | struct hda_bus *bus = codec->bus; | ||
115 | |||
116 | if ((power_up && codec->pm_up_notified) || | ||
117 | (!power_up && !codec->pm_up_notified)) | ||
118 | return; | ||
119 | if (bus->ops.pm_notify) | ||
120 | bus->ops.pm_notify(bus, power_up); | ||
121 | codec->pm_up_notified = power_up; | ||
122 | } | ||
123 | |||
124 | #else | 49 | #else |
125 | #define codec_in_pm(codec) 0 | 50 | #define codec_in_pm(codec) 0 |
126 | static inline void hda_keep_power_on(struct hda_codec *codec) {} | ||
127 | #define hda_codec_is_power_on(codec) 1 | 51 | #define hda_codec_is_power_on(codec) 1 |
128 | #define hda_call_pm_notify(codec, state) {} | ||
129 | #endif | 52 | #endif |
130 | 53 | ||
131 | /** | 54 | /** |
@@ -885,111 +808,6 @@ int snd_hda_bus_new(struct snd_card *card, | |||
885 | } | 808 | } |
886 | EXPORT_SYMBOL_GPL(snd_hda_bus_new); | 809 | EXPORT_SYMBOL_GPL(snd_hda_bus_new); |
887 | 810 | ||
888 | #if IS_ENABLED(CONFIG_SND_HDA_GENERIC) | ||
889 | #define is_generic_config(codec) \ | ||
890 | (codec->modelname && !strcmp(codec->modelname, "generic")) | ||
891 | #else | ||
892 | #define is_generic_config(codec) 0 | ||
893 | #endif | ||
894 | |||
895 | #ifdef MODULE | ||
896 | #define HDA_MODREQ_MAX_COUNT 2 /* two request_modules()'s */ | ||
897 | #else | ||
898 | #define HDA_MODREQ_MAX_COUNT 0 /* all presets are statically linked */ | ||
899 | #endif | ||
900 | |||
901 | /* | ||
902 | * find a matching codec preset | ||
903 | */ | ||
904 | static const struct hda_codec_preset * | ||
905 | find_codec_preset(struct hda_codec *codec) | ||
906 | { | ||
907 | struct hda_codec_preset_list *tbl; | ||
908 | const struct hda_codec_preset *preset; | ||
909 | unsigned int mod_requested = 0; | ||
910 | |||
911 | again: | ||
912 | mutex_lock(&preset_mutex); | ||
913 | list_for_each_entry(tbl, &hda_preset_tables, list) { | ||
914 | if (!try_module_get(tbl->owner)) { | ||
915 | codec_err(codec, "cannot module_get\n"); | ||
916 | continue; | ||
917 | } | ||
918 | for (preset = tbl->preset; preset->id; preset++) { | ||
919 | u32 mask = preset->mask; | ||
920 | if (preset->afg && preset->afg != codec->afg) | ||
921 | continue; | ||
922 | if (preset->mfg && preset->mfg != codec->mfg) | ||
923 | continue; | ||
924 | if (!mask) | ||
925 | mask = ~0; | ||
926 | if (preset->id == (codec->vendor_id & mask) && | ||
927 | (!preset->rev || | ||
928 | preset->rev == codec->revision_id)) { | ||
929 | mutex_unlock(&preset_mutex); | ||
930 | codec->owner = tbl->owner; | ||
931 | return preset; | ||
932 | } | ||
933 | } | ||
934 | module_put(tbl->owner); | ||
935 | } | ||
936 | mutex_unlock(&preset_mutex); | ||
937 | |||
938 | if (mod_requested < HDA_MODREQ_MAX_COUNT) { | ||
939 | if (!mod_requested) | ||
940 | request_module("snd-hda-codec-id:%08x", | ||
941 | codec->vendor_id); | ||
942 | else | ||
943 | request_module("snd-hda-codec-id:%04x*", | ||
944 | (codec->vendor_id >> 16) & 0xffff); | ||
945 | mod_requested++; | ||
946 | goto again; | ||
947 | } | ||
948 | return NULL; | ||
949 | } | ||
950 | |||
951 | /* | ||
952 | * get_codec_name - store the codec name | ||
953 | */ | ||
954 | static int get_codec_name(struct hda_codec *codec) | ||
955 | { | ||
956 | const struct hda_vendor_id *c; | ||
957 | const char *vendor = NULL; | ||
958 | u16 vendor_id = codec->vendor_id >> 16; | ||
959 | char tmp[16]; | ||
960 | |||
961 | if (codec->vendor_name) | ||
962 | goto get_chip_name; | ||
963 | |||
964 | for (c = hda_vendor_ids; c->id; c++) { | ||
965 | if (c->id == vendor_id) { | ||
966 | vendor = c->name; | ||
967 | break; | ||
968 | } | ||
969 | } | ||
970 | if (!vendor) { | ||
971 | sprintf(tmp, "Generic %04x", vendor_id); | ||
972 | vendor = tmp; | ||
973 | } | ||
974 | codec->vendor_name = kstrdup(vendor, GFP_KERNEL); | ||
975 | if (!codec->vendor_name) | ||
976 | return -ENOMEM; | ||
977 | |||
978 | get_chip_name: | ||
979 | if (codec->chip_name) | ||
980 | return 0; | ||
981 | |||
982 | if (codec->preset && codec->preset->name) | ||
983 | codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL); | ||
984 | else { | ||
985 | sprintf(tmp, "ID %x", codec->vendor_id & 0xffff); | ||
986 | codec->chip_name = kstrdup(tmp, GFP_KERNEL); | ||
987 | } | ||
988 | if (!codec->chip_name) | ||
989 | return -ENOMEM; | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | /* | 811 | /* |
994 | * look for an AFG and MFG nodes | 812 | * look for an AFG and MFG nodes |
995 | */ | 813 | */ |
@@ -1301,20 +1119,6 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) | |||
1301 | } | 1119 | } |
1302 | 1120 | ||
1303 | /* | 1121 | /* |
1304 | * Dynamic symbol binding for the codec parsers | ||
1305 | */ | ||
1306 | |||
1307 | #define load_parser(codec, sym) \ | ||
1308 | ((codec)->parser = (int (*)(struct hda_codec *))symbol_request(sym)) | ||
1309 | |||
1310 | static void unload_parser(struct hda_codec *codec) | ||
1311 | { | ||
1312 | if (codec->parser) | ||
1313 | symbol_put_addr(codec->parser); | ||
1314 | codec->parser = NULL; | ||
1315 | } | ||
1316 | |||
1317 | /* | ||
1318 | * codec destructor | 1122 | * codec destructor |
1319 | */ | 1123 | */ |
1320 | static void snd_hda_codec_free(struct hda_codec *codec) | 1124 | static void snd_hda_codec_free(struct hda_codec *codec) |
@@ -1322,12 +1126,11 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
1322 | if (!codec) | 1126 | if (!codec) |
1323 | return; | 1127 | return; |
1324 | cancel_delayed_work_sync(&codec->jackpoll_work); | 1128 | cancel_delayed_work_sync(&codec->jackpoll_work); |
1129 | if (device_is_registered(hda_codec_dev(codec))) | ||
1130 | device_del(hda_codec_dev(codec)); | ||
1325 | snd_hda_jack_tbl_clear(codec); | 1131 | snd_hda_jack_tbl_clear(codec); |
1326 | free_init_pincfgs(codec); | 1132 | free_init_pincfgs(codec); |
1327 | #ifdef CONFIG_PM | ||
1328 | cancel_delayed_work(&codec->power_work); | ||
1329 | flush_workqueue(codec->bus->workq); | 1133 | flush_workqueue(codec->bus->workq); |
1330 | #endif | ||
1331 | list_del(&codec->list); | 1134 | list_del(&codec->list); |
1332 | snd_array_free(&codec->mixers); | 1135 | snd_array_free(&codec->mixers); |
1333 | snd_array_free(&codec->nids); | 1136 | snd_array_free(&codec->nids); |
@@ -1335,12 +1138,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
1335 | snd_array_free(&codec->spdif_out); | 1138 | snd_array_free(&codec->spdif_out); |
1336 | remove_conn_list(codec); | 1139 | remove_conn_list(codec); |
1337 | codec->bus->caddr_tbl[codec->addr] = NULL; | 1140 | codec->bus->caddr_tbl[codec->addr] = NULL; |
1338 | if (codec->patch_ops.free) | 1141 | clear_bit(codec->addr, &codec->bus->codec_powered); |
1339 | codec->patch_ops.free(codec); | ||
1340 | hda_call_pm_notify(codec, false); /* cancel leftover refcounts */ | ||
1341 | snd_hda_sysfs_clear(codec); | 1142 | snd_hda_sysfs_clear(codec); |
1342 | unload_parser(codec); | ||
1343 | module_put(codec->owner); | ||
1344 | free_hda_cache(&codec->amp_cache); | 1143 | free_hda_cache(&codec->amp_cache); |
1345 | free_hda_cache(&codec->cmd_cache); | 1144 | free_hda_cache(&codec->cmd_cache); |
1346 | kfree(codec->vendor_name); | 1145 | kfree(codec->vendor_name); |
@@ -1348,7 +1147,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
1348 | kfree(codec->modelname); | 1147 | kfree(codec->modelname); |
1349 | kfree(codec->wcaps); | 1148 | kfree(codec->wcaps); |
1350 | codec->bus->num_codecs--; | 1149 | codec->bus->num_codecs--; |
1351 | put_device(&codec->dev); | 1150 | put_device(hda_codec_dev(codec)); |
1352 | } | 1151 | } |
1353 | 1152 | ||
1354 | static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, | 1153 | static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, |
@@ -1360,11 +1159,12 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, | |||
1360 | static int snd_hda_codec_dev_register(struct snd_device *device) | 1159 | static int snd_hda_codec_dev_register(struct snd_device *device) |
1361 | { | 1160 | { |
1362 | struct hda_codec *codec = device->device_data; | 1161 | struct hda_codec *codec = device->device_data; |
1363 | int err = device_add(&codec->dev); | ||
1364 | 1162 | ||
1365 | if (err < 0) | ||
1366 | return err; | ||
1367 | snd_hda_register_beep_device(codec); | 1163 | snd_hda_register_beep_device(codec); |
1164 | if (device_is_registered(hda_codec_dev(codec))) | ||
1165 | pm_runtime_enable(hda_codec_dev(codec)); | ||
1166 | /* it was powered up in snd_hda_codec_new(), now all done */ | ||
1167 | snd_hda_power_down(codec); | ||
1368 | return 0; | 1168 | return 0; |
1369 | } | 1169 | } |
1370 | 1170 | ||
@@ -1373,7 +1173,6 @@ static int snd_hda_codec_dev_disconnect(struct snd_device *device) | |||
1373 | struct hda_codec *codec = device->device_data; | 1173 | struct hda_codec *codec = device->device_data; |
1374 | 1174 | ||
1375 | snd_hda_detach_beep_device(codec); | 1175 | snd_hda_detach_beep_device(codec); |
1376 | device_del(&codec->dev); | ||
1377 | return 0; | 1176 | return 0; |
1378 | } | 1177 | } |
1379 | 1178 | ||
@@ -1386,7 +1185,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) | |||
1386 | /* just free the container */ | 1185 | /* just free the container */ |
1387 | static void snd_hda_codec_dev_release(struct device *dev) | 1186 | static void snd_hda_codec_dev_release(struct device *dev) |
1388 | { | 1187 | { |
1389 | kfree(container_of(dev, struct hda_codec, dev)); | 1188 | kfree(dev_to_hda_codec(dev)); |
1390 | } | 1189 | } |
1391 | 1190 | ||
1392 | /** | 1191 | /** |
@@ -1402,6 +1201,7 @@ int snd_hda_codec_new(struct hda_bus *bus, | |||
1402 | struct hda_codec **codecp) | 1201 | struct hda_codec **codecp) |
1403 | { | 1202 | { |
1404 | struct hda_codec *codec; | 1203 | struct hda_codec *codec; |
1204 | struct device *dev; | ||
1405 | char component[31]; | 1205 | char component[31]; |
1406 | hda_nid_t fg; | 1206 | hda_nid_t fg; |
1407 | int err; | 1207 | int err; |
@@ -1429,14 +1229,15 @@ int snd_hda_codec_new(struct hda_bus *bus, | |||
1429 | return -ENOMEM; | 1229 | return -ENOMEM; |
1430 | } | 1230 | } |
1431 | 1231 | ||
1432 | device_initialize(&codec->dev); | 1232 | dev = hda_codec_dev(codec); |
1433 | codec->dev.parent = &bus->card->card_dev; | 1233 | device_initialize(dev); |
1434 | codec->dev.class = sound_class; | 1234 | dev->parent = bus->card->dev; |
1435 | codec->dev.release = snd_hda_codec_dev_release; | 1235 | dev->bus = &snd_hda_bus_type; |
1436 | codec->dev.groups = snd_hda_dev_attr_groups; | 1236 | dev->release = snd_hda_codec_dev_release; |
1437 | dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number, | 1237 | dev->groups = snd_hda_dev_attr_groups; |
1438 | codec_addr); | 1238 | dev_set_name(dev, "hdaudioC%dD%d", bus->card->number, codec_addr); |
1439 | dev_set_drvdata(&codec->dev, codec); /* for sysfs */ | 1239 | dev_set_drvdata(dev, codec); /* for sysfs */ |
1240 | device_enable_async_suspend(dev); | ||
1440 | 1241 | ||
1441 | codec->bus = bus; | 1242 | codec->bus = bus; |
1442 | codec->addr = codec_addr; | 1243 | codec->addr = codec_addr; |
@@ -1460,13 +1261,13 @@ int snd_hda_codec_new(struct hda_bus *bus, | |||
1460 | codec->fixup_id = HDA_FIXUP_ID_NOT_SET; | 1261 | codec->fixup_id = HDA_FIXUP_ID_NOT_SET; |
1461 | 1262 | ||
1462 | #ifdef CONFIG_PM | 1263 | #ifdef CONFIG_PM |
1463 | spin_lock_init(&codec->power_lock); | ||
1464 | INIT_DELAYED_WORK(&codec->power_work, hda_power_work); | ||
1465 | /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. | 1264 | /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. |
1466 | * the caller has to power down appropriatley after initialization | 1265 | * it's powered down later in snd_hda_codec_dev_register(). |
1467 | * phase. | ||
1468 | */ | 1266 | */ |
1469 | hda_keep_power_on(codec); | 1267 | set_bit(codec->addr, &bus->codec_powered); |
1268 | pm_runtime_set_active(hda_codec_dev(codec)); | ||
1269 | pm_runtime_get_noresume(hda_codec_dev(codec)); | ||
1270 | codec->power_jiffies = jiffies; | ||
1470 | #endif | 1271 | #endif |
1471 | 1272 | ||
1472 | snd_hda_sysfs_init(codec); | 1273 | snd_hda_sysfs_init(codec); |
@@ -1526,11 +1327,6 @@ int snd_hda_codec_new(struct hda_bus *bus, | |||
1526 | #endif | 1327 | #endif |
1527 | codec->epss = snd_hda_codec_get_supported_ps(codec, fg, | 1328 | codec->epss = snd_hda_codec_get_supported_ps(codec, fg, |
1528 | AC_PWRST_EPSS); | 1329 | AC_PWRST_EPSS); |
1529 | #ifdef CONFIG_PM | ||
1530 | if (!codec->d3_stop_clk || !codec->epss) | ||
1531 | bus->power_keep_link_on = 1; | ||
1532 | #endif | ||
1533 | |||
1534 | 1330 | ||
1535 | /* power-up all before initialization */ | 1331 | /* power-up all before initialization */ |
1536 | hda_set_power_state(codec, AC_PWRST_D0); | 1332 | hda_set_power_state(codec, AC_PWRST_D0); |
@@ -1587,92 +1383,6 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) | |||
1587 | } | 1383 | } |
1588 | EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets); | 1384 | EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets); |
1589 | 1385 | ||
1590 | |||
1591 | #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) | ||
1592 | /* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */ | ||
1593 | static bool is_likely_hdmi_codec(struct hda_codec *codec) | ||
1594 | { | ||
1595 | hda_nid_t nid = codec->start_nid; | ||
1596 | int i; | ||
1597 | |||
1598 | for (i = 0; i < codec->num_nodes; i++, nid++) { | ||
1599 | unsigned int wcaps = get_wcaps(codec, nid); | ||
1600 | switch (get_wcaps_type(wcaps)) { | ||
1601 | case AC_WID_AUD_IN: | ||
1602 | return false; /* HDMI parser supports only HDMI out */ | ||
1603 | case AC_WID_AUD_OUT: | ||
1604 | if (!(wcaps & AC_WCAP_DIGITAL)) | ||
1605 | return false; | ||
1606 | break; | ||
1607 | } | ||
1608 | } | ||
1609 | return true; | ||
1610 | } | ||
1611 | #else | ||
1612 | /* no HDMI codec parser support */ | ||
1613 | #define is_likely_hdmi_codec(codec) false | ||
1614 | #endif /* CONFIG_SND_HDA_CODEC_HDMI */ | ||
1615 | |||
1616 | /** | ||
1617 | * snd_hda_codec_configure - (Re-)configure the HD-audio codec | ||
1618 | * @codec: the HDA codec | ||
1619 | * | ||
1620 | * Start parsing of the given codec tree and (re-)initialize the whole | ||
1621 | * patch instance. | ||
1622 | * | ||
1623 | * Returns 0 if successful or a negative error code. | ||
1624 | */ | ||
1625 | int snd_hda_codec_configure(struct hda_codec *codec) | ||
1626 | { | ||
1627 | int (*patch)(struct hda_codec *) = NULL; | ||
1628 | int err; | ||
1629 | |||
1630 | codec->preset = find_codec_preset(codec); | ||
1631 | if (!codec->vendor_name || !codec->chip_name) { | ||
1632 | err = get_codec_name(codec); | ||
1633 | if (err < 0) | ||
1634 | return err; | ||
1635 | } | ||
1636 | |||
1637 | if (!is_generic_config(codec) && codec->preset) | ||
1638 | patch = codec->preset->patch; | ||
1639 | if (!patch) { | ||
1640 | unload_parser(codec); /* to be sure */ | ||
1641 | if (is_likely_hdmi_codec(codec)) { | ||
1642 | #if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI) | ||
1643 | patch = load_parser(codec, snd_hda_parse_hdmi_codec); | ||
1644 | #elif IS_BUILTIN(CONFIG_SND_HDA_CODEC_HDMI) | ||
1645 | patch = snd_hda_parse_hdmi_codec; | ||
1646 | #endif | ||
1647 | } | ||
1648 | if (!patch) { | ||
1649 | #if IS_MODULE(CONFIG_SND_HDA_GENERIC) | ||
1650 | patch = load_parser(codec, snd_hda_parse_generic_codec); | ||
1651 | #elif IS_BUILTIN(CONFIG_SND_HDA_GENERIC) | ||
1652 | patch = snd_hda_parse_generic_codec; | ||
1653 | #endif | ||
1654 | } | ||
1655 | if (!patch) { | ||
1656 | codec_err(codec, "No codec parser is available\n"); | ||
1657 | return -ENODEV; | ||
1658 | } | ||
1659 | } | ||
1660 | |||
1661 | err = patch(codec); | ||
1662 | if (err < 0) { | ||
1663 | unload_parser(codec); | ||
1664 | return err; | ||
1665 | } | ||
1666 | |||
1667 | /* audio codec should override the mixer name */ | ||
1668 | if (codec->afg || !*codec->bus->card->mixername) | ||
1669 | snprintf(codec->bus->card->mixername, | ||
1670 | sizeof(codec->bus->card->mixername), | ||
1671 | "%s %s", codec->vendor_name, codec->chip_name); | ||
1672 | return 0; | ||
1673 | } | ||
1674 | EXPORT_SYMBOL_GPL(snd_hda_codec_configure); | ||
1675 | |||
1676 | /* update the stream-id if changed */ | 1386 | /* update the stream-id if changed */ |
1677 | static void update_pcm_stream_id(struct hda_codec *codec, | 1387 | static void update_pcm_stream_id(struct hda_codec *codec, |
1678 | struct hda_cvt_setup *p, hda_nid_t nid, | 1388 | struct hda_cvt_setup *p, hda_nid_t nid, |
@@ -2725,10 +2435,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) | |||
2725 | 2435 | ||
2726 | /* OK, let it free */ | 2436 | /* OK, let it free */ |
2727 | cancel_delayed_work_sync(&codec->jackpoll_work); | 2437 | cancel_delayed_work_sync(&codec->jackpoll_work); |
2728 | #ifdef CONFIG_PM | ||
2729 | cancel_delayed_work_sync(&codec->power_work); | ||
2730 | flush_workqueue(bus->workq); | 2438 | flush_workqueue(bus->workq); |
2731 | #endif | ||
2732 | snd_hda_ctls_clear(codec); | 2439 | snd_hda_ctls_clear(codec); |
2733 | /* release PCMs */ | 2440 | /* release PCMs */ |
2734 | for (i = 0; i < codec->num_pcms; i++) { | 2441 | for (i = 0; i < codec->num_pcms; i++) { |
@@ -2739,8 +2446,9 @@ int snd_hda_codec_reset(struct hda_codec *codec) | |||
2739 | } | 2446 | } |
2740 | } | 2447 | } |
2741 | snd_hda_detach_beep_device(codec); | 2448 | snd_hda_detach_beep_device(codec); |
2742 | if (codec->patch_ops.free) | 2449 | if (device_is_registered(hda_codec_dev(codec))) |
2743 | codec->patch_ops.free(codec); | 2450 | device_del(hda_codec_dev(codec)); |
2451 | |||
2744 | memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); | 2452 | memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); |
2745 | snd_hda_jack_tbl_clear(codec); | 2453 | snd_hda_jack_tbl_clear(codec); |
2746 | codec->proc_widget_hook = NULL; | 2454 | codec->proc_widget_hook = NULL; |
@@ -2759,9 +2467,6 @@ int snd_hda_codec_reset(struct hda_codec *codec) | |||
2759 | codec->preset = NULL; | 2467 | codec->preset = NULL; |
2760 | codec->slave_dig_outs = NULL; | 2468 | codec->slave_dig_outs = NULL; |
2761 | codec->spdif_status_reset = 0; | 2469 | codec->spdif_status_reset = 0; |
2762 | unload_parser(codec); | ||
2763 | module_put(codec->owner); | ||
2764 | codec->owner = NULL; | ||
2765 | 2470 | ||
2766 | /* allow device access again */ | 2471 | /* allow device access again */ |
2767 | snd_hda_unlock_devices(bus); | 2472 | snd_hda_unlock_devices(bus); |
@@ -4167,31 +3872,40 @@ static inline void hda_exec_init_verbs(struct hda_codec *codec) {} | |||
4167 | #endif | 3872 | #endif |
4168 | 3873 | ||
4169 | #ifdef CONFIG_PM | 3874 | #ifdef CONFIG_PM |
3875 | /* update the power on/off account with the current jiffies */ | ||
3876 | static void update_power_acct(struct hda_codec *codec, bool on) | ||
3877 | { | ||
3878 | unsigned long delta = jiffies - codec->power_jiffies; | ||
3879 | |||
3880 | if (on) | ||
3881 | codec->power_on_acct += delta; | ||
3882 | else | ||
3883 | codec->power_off_acct += delta; | ||
3884 | codec->power_jiffies += delta; | ||
3885 | } | ||
3886 | |||
3887 | void snd_hda_update_power_acct(struct hda_codec *codec) | ||
3888 | { | ||
3889 | update_power_acct(codec, hda_codec_is_power_on(codec)); | ||
3890 | } | ||
3891 | |||
4170 | /* | 3892 | /* |
4171 | * call suspend and power-down; used both from PM and power-save | 3893 | * call suspend and power-down; used both from PM and power-save |
4172 | * this function returns the power state in the end | 3894 | * this function returns the power state in the end |
4173 | */ | 3895 | */ |
4174 | static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) | 3896 | static unsigned int hda_call_codec_suspend(struct hda_codec *codec) |
4175 | { | 3897 | { |
4176 | unsigned int state; | 3898 | unsigned int state; |
4177 | 3899 | ||
4178 | codec->in_pm = 1; | 3900 | atomic_inc(&codec->in_pm); |
4179 | 3901 | ||
4180 | if (codec->patch_ops.suspend) | 3902 | if (codec->patch_ops.suspend) |
4181 | codec->patch_ops.suspend(codec); | 3903 | codec->patch_ops.suspend(codec); |
4182 | hda_cleanup_all_streams(codec); | 3904 | hda_cleanup_all_streams(codec); |
4183 | state = hda_set_power_state(codec, AC_PWRST_D3); | 3905 | state = hda_set_power_state(codec, AC_PWRST_D3); |
4184 | /* Cancel delayed work if we aren't currently running from it. */ | ||
4185 | if (!in_wq) | ||
4186 | cancel_delayed_work_sync(&codec->power_work); | ||
4187 | spin_lock(&codec->power_lock); | ||
4188 | snd_hda_update_power_acct(codec); | ||
4189 | trace_hda_power_down(codec); | 3906 | trace_hda_power_down(codec); |
4190 | codec->power_on = 0; | 3907 | update_power_acct(codec, true); |
4191 | codec->power_transition = 0; | 3908 | atomic_dec(&codec->in_pm); |
4192 | codec->power_jiffies = jiffies; | ||
4193 | spin_unlock(&codec->power_lock); | ||
4194 | codec->in_pm = 0; | ||
4195 | return state; | 3909 | return state; |
4196 | } | 3910 | } |
4197 | 3911 | ||
@@ -4216,14 +3930,13 @@ static void hda_mark_cmd_cache_dirty(struct hda_codec *codec) | |||
4216 | */ | 3930 | */ |
4217 | static void hda_call_codec_resume(struct hda_codec *codec) | 3931 | static void hda_call_codec_resume(struct hda_codec *codec) |
4218 | { | 3932 | { |
4219 | codec->in_pm = 1; | 3933 | atomic_inc(&codec->in_pm); |
4220 | 3934 | ||
3935 | trace_hda_power_up(codec); | ||
4221 | hda_mark_cmd_cache_dirty(codec); | 3936 | hda_mark_cmd_cache_dirty(codec); |
4222 | 3937 | ||
4223 | /* set as if powered on for avoiding re-entering the resume | 3938 | codec->power_jiffies = jiffies; |
4224 | * in the resume / power-save sequence | 3939 | |
4225 | */ | ||
4226 | hda_keep_power_on(codec); | ||
4227 | hda_set_power_state(codec, AC_PWRST_D0); | 3940 | hda_set_power_state(codec, AC_PWRST_D0); |
4228 | restore_shutup_pins(codec); | 3941 | restore_shutup_pins(codec); |
4229 | hda_exec_init_verbs(codec); | 3942 | hda_exec_init_verbs(codec); |
@@ -4241,12 +3954,42 @@ static void hda_call_codec_resume(struct hda_codec *codec) | |||
4241 | hda_jackpoll_work(&codec->jackpoll_work.work); | 3954 | hda_jackpoll_work(&codec->jackpoll_work.work); |
4242 | else | 3955 | else |
4243 | snd_hda_jack_report_sync(codec); | 3956 | snd_hda_jack_report_sync(codec); |
3957 | atomic_dec(&codec->in_pm); | ||
3958 | } | ||
3959 | |||
3960 | static int hda_codec_runtime_suspend(struct device *dev) | ||
3961 | { | ||
3962 | struct hda_codec *codec = dev_to_hda_codec(dev); | ||
3963 | unsigned int state; | ||
3964 | int i; | ||
3965 | |||
3966 | cancel_delayed_work_sync(&codec->jackpoll_work); | ||
3967 | for (i = 0; i < codec->num_pcms; i++) | ||
3968 | snd_pcm_suspend_all(codec->pcm_info[i].pcm); | ||
3969 | state = hda_call_codec_suspend(codec); | ||
3970 | if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK)) | ||
3971 | clear_bit(codec->addr, &codec->bus->codec_powered); | ||
3972 | return 0; | ||
3973 | } | ||
3974 | |||
3975 | static int hda_codec_runtime_resume(struct device *dev) | ||
3976 | { | ||
3977 | struct hda_codec *codec = dev_to_hda_codec(dev); | ||
4244 | 3978 | ||
4245 | codec->in_pm = 0; | 3979 | set_bit(codec->addr, &codec->bus->codec_powered); |
4246 | snd_hda_power_down(codec); /* flag down before returning */ | 3980 | hda_call_codec_resume(codec); |
3981 | pm_runtime_mark_last_busy(dev); | ||
3982 | return 0; | ||
4247 | } | 3983 | } |
4248 | #endif /* CONFIG_PM */ | 3984 | #endif /* CONFIG_PM */ |
4249 | 3985 | ||
3986 | /* referred in hda_bind.c */ | ||
3987 | const struct dev_pm_ops hda_codec_driver_pm = { | ||
3988 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
3989 | pm_runtime_force_resume) | ||
3990 | SET_RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, | ||
3991 | NULL) | ||
3992 | }; | ||
4250 | 3993 | ||
4251 | /** | 3994 | /** |
4252 | * snd_hda_build_controls - build mixer controls | 3995 | * snd_hda_build_controls - build mixer controls |
@@ -4984,127 +4727,70 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, | |||
4984 | EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); | 4727 | EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); |
4985 | 4728 | ||
4986 | #ifdef CONFIG_PM | 4729 | #ifdef CONFIG_PM |
4987 | static void hda_power_work(struct work_struct *work) | 4730 | /** |
4731 | * snd_hda_power_up - Power-up the codec | ||
4732 | * @codec: HD-audio codec | ||
4733 | * | ||
4734 | * Increment the usage counter and resume the device if not done yet. | ||
4735 | */ | ||
4736 | void snd_hda_power_up(struct hda_codec *codec) | ||
4988 | { | 4737 | { |
4989 | struct hda_codec *codec = | 4738 | struct device *dev = hda_codec_dev(codec); |
4990 | container_of(work, struct hda_codec, power_work.work); | ||
4991 | struct hda_bus *bus = codec->bus; | ||
4992 | unsigned int state; | ||
4993 | 4739 | ||
4994 | spin_lock(&codec->power_lock); | 4740 | if (codec_in_pm(codec)) |
4995 | if (codec->power_transition > 0) { /* during power-up sequence? */ | ||
4996 | spin_unlock(&codec->power_lock); | ||
4997 | return; | ||
4998 | } | ||
4999 | if (!codec->power_on || codec->power_count) { | ||
5000 | codec->power_transition = 0; | ||
5001 | spin_unlock(&codec->power_lock); | ||
5002 | return; | 4741 | return; |
5003 | } | 4742 | pm_runtime_get_sync(dev); |
5004 | spin_unlock(&codec->power_lock); | ||
5005 | |||
5006 | state = hda_call_codec_suspend(codec, true); | ||
5007 | if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) | ||
5008 | hda_call_pm_notify(codec, false); | ||
5009 | } | ||
5010 | |||
5011 | static void hda_keep_power_on(struct hda_codec *codec) | ||
5012 | { | ||
5013 | spin_lock(&codec->power_lock); | ||
5014 | codec->power_count++; | ||
5015 | codec->power_on = 1; | ||
5016 | codec->power_jiffies = jiffies; | ||
5017 | spin_unlock(&codec->power_lock); | ||
5018 | hda_call_pm_notify(codec, true); | ||
5019 | } | 4743 | } |
4744 | EXPORT_SYMBOL_GPL(snd_hda_power_up); | ||
5020 | 4745 | ||
5021 | /* update the power on/off account with the current jiffies */ | 4746 | /** |
5022 | void snd_hda_update_power_acct(struct hda_codec *codec) | 4747 | * snd_hda_power_down - Power-down the codec |
5023 | { | 4748 | * @codec: HD-audio codec |
5024 | unsigned long delta = jiffies - codec->power_jiffies; | 4749 | * |
5025 | if (codec->power_on) | 4750 | * Decrement the usage counter and schedules the autosuspend if none used. |
5026 | codec->power_on_acct += delta; | 4751 | */ |
5027 | else | 4752 | void snd_hda_power_down(struct hda_codec *codec) |
5028 | codec->power_off_acct += delta; | ||
5029 | codec->power_jiffies += delta; | ||
5030 | } | ||
5031 | |||
5032 | /* Transition to powered up, if wait_power_down then wait for a pending | ||
5033 | * transition to D3 to complete. A pending D3 transition is indicated | ||
5034 | * with power_transition == -1. */ | ||
5035 | /* call this with codec->power_lock held! */ | ||
5036 | static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) | ||
5037 | { | 4753 | { |
5038 | /* Return if power_on or transitioning to power_on, unless currently | 4754 | struct device *dev = hda_codec_dev(codec); |
5039 | * powering down. */ | ||
5040 | if ((codec->power_on || codec->power_transition > 0) && | ||
5041 | !(wait_power_down && codec->power_transition < 0)) | ||
5042 | return; | ||
5043 | spin_unlock(&codec->power_lock); | ||
5044 | |||
5045 | cancel_delayed_work_sync(&codec->power_work); | ||
5046 | 4755 | ||
5047 | spin_lock(&codec->power_lock); | 4756 | if (codec_in_pm(codec)) |
5048 | /* If the power down delayed work was cancelled above before starting, | ||
5049 | * then there is no need to go through power up here. | ||
5050 | */ | ||
5051 | if (codec->power_on) { | ||
5052 | if (codec->power_transition < 0) | ||
5053 | codec->power_transition = 0; | ||
5054 | return; | 4757 | return; |
5055 | } | 4758 | pm_runtime_mark_last_busy(dev); |
5056 | 4759 | pm_runtime_put_autosuspend(dev); | |
5057 | trace_hda_power_up(codec); | ||
5058 | snd_hda_update_power_acct(codec); | ||
5059 | codec->power_on = 1; | ||
5060 | codec->power_jiffies = jiffies; | ||
5061 | codec->power_transition = 1; /* avoid reentrance */ | ||
5062 | spin_unlock(&codec->power_lock); | ||
5063 | |||
5064 | hda_call_codec_resume(codec); | ||
5065 | |||
5066 | spin_lock(&codec->power_lock); | ||
5067 | codec->power_transition = 0; | ||
5068 | } | 4760 | } |
4761 | EXPORT_SYMBOL_GPL(snd_hda_power_down); | ||
5069 | 4762 | ||
5070 | #define power_save(codec) \ | 4763 | static void codec_set_power_save(struct hda_codec *codec, int delay) |
5071 | ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) | ||
5072 | |||
5073 | /* Transition to powered down */ | ||
5074 | static void __snd_hda_power_down(struct hda_codec *codec) | ||
5075 | { | 4764 | { |
5076 | if (!codec->power_on || codec->power_count || codec->power_transition) | 4765 | struct device *dev = hda_codec_dev(codec); |
5077 | return; | ||
5078 | 4766 | ||
5079 | if (power_save(codec)) { | 4767 | if (delay > 0) { |
5080 | codec->power_transition = -1; /* avoid reentrance */ | 4768 | pm_runtime_set_autosuspend_delay(dev, delay); |
5081 | queue_delayed_work(codec->bus->workq, &codec->power_work, | 4769 | pm_runtime_use_autosuspend(dev); |
5082 | msecs_to_jiffies(power_save(codec) * 1000)); | 4770 | pm_runtime_allow(dev); |
4771 | if (!pm_runtime_suspended(dev)) | ||
4772 | pm_runtime_mark_last_busy(dev); | ||
4773 | } else { | ||
4774 | pm_runtime_dont_use_autosuspend(dev); | ||
4775 | pm_runtime_forbid(dev); | ||
5083 | } | 4776 | } |
5084 | } | 4777 | } |
5085 | 4778 | ||
5086 | /** | 4779 | /** |
5087 | * snd_hda_power_save - Power-up/down/sync the codec | 4780 | * snd_hda_set_power_save - reprogram autosuspend for the given delay |
5088 | * @codec: HD-audio codec | 4781 | * @bus: HD-audio bus |
5089 | * @delta: the counter delta to change | 4782 | * @delay: autosuspend delay in msec, 0 = off |
5090 | * @d3wait: sync for D3 transition complete | ||
5091 | * | 4783 | * |
5092 | * Change the power-up counter via @delta, and power up or down the hardware | 4784 | * Synchronize the runtime PM autosuspend state from the power_save option. |
5093 | * appropriately. For the power-down, queue to the delayed action. | ||
5094 | * Passing zero to @delta means to synchronize the power state. | ||
5095 | */ | 4785 | */ |
5096 | void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait) | 4786 | void snd_hda_set_power_save(struct hda_bus *bus, int delay) |
5097 | { | 4787 | { |
5098 | spin_lock(&codec->power_lock); | 4788 | struct hda_codec *c; |
5099 | codec->power_count += delta; | 4789 | |
5100 | trace_hda_power_count(codec); | 4790 | list_for_each_entry(c, &bus->codec_list, list) |
5101 | if (delta > 0) | 4791 | codec_set_power_save(c, delay); |
5102 | __snd_hda_power_up(codec, d3wait); | ||
5103 | else | ||
5104 | __snd_hda_power_down(codec); | ||
5105 | spin_unlock(&codec->power_lock); | ||
5106 | } | 4792 | } |
5107 | EXPORT_SYMBOL_GPL(snd_hda_power_save); | 4793 | EXPORT_SYMBOL_GPL(snd_hda_set_power_save); |
5108 | 4794 | ||
5109 | /** | 4795 | /** |
5110 | * snd_hda_check_amp_list_power - Check the amp list and update the power | 4796 | * snd_hda_check_amp_list_power - Check the amp list and update the power |
@@ -5158,88 +4844,6 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); | |||
5158 | #endif | 4844 | #endif |
5159 | 4845 | ||
5160 | /* | 4846 | /* |
5161 | * Channel mode helper | ||
5162 | */ | ||
5163 | |||
5164 | /** | ||
5165 | * snd_hda_ch_mode_info - Info callback helper for the channel mode enum | ||
5166 | * @codec: the HDA codec | ||
5167 | * @uinfo: pointer to get/store the data | ||
5168 | * @chmode: channel mode array | ||
5169 | * @num_chmodes: channel mode array size | ||
5170 | */ | ||
5171 | int snd_hda_ch_mode_info(struct hda_codec *codec, | ||
5172 | struct snd_ctl_elem_info *uinfo, | ||
5173 | const struct hda_channel_mode *chmode, | ||
5174 | int num_chmodes) | ||
5175 | { | ||
5176 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
5177 | uinfo->count = 1; | ||
5178 | uinfo->value.enumerated.items = num_chmodes; | ||
5179 | if (uinfo->value.enumerated.item >= num_chmodes) | ||
5180 | uinfo->value.enumerated.item = num_chmodes - 1; | ||
5181 | sprintf(uinfo->value.enumerated.name, "%dch", | ||
5182 | chmode[uinfo->value.enumerated.item].channels); | ||
5183 | return 0; | ||
5184 | } | ||
5185 | EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info); | ||
5186 | |||
5187 | /** | ||
5188 | * snd_hda_ch_mode_get - Get callback helper for the channel mode enum | ||
5189 | * @codec: the HDA codec | ||
5190 | * @ucontrol: pointer to get/store the data | ||
5191 | * @chmode: channel mode array | ||
5192 | * @num_chmodes: channel mode array size | ||
5193 | * @max_channels: max number of channels | ||
5194 | */ | ||
5195 | int snd_hda_ch_mode_get(struct hda_codec *codec, | ||
5196 | struct snd_ctl_elem_value *ucontrol, | ||
5197 | const struct hda_channel_mode *chmode, | ||
5198 | int num_chmodes, | ||
5199 | int max_channels) | ||
5200 | { | ||
5201 | int i; | ||
5202 | |||
5203 | for (i = 0; i < num_chmodes; i++) { | ||
5204 | if (max_channels == chmode[i].channels) { | ||
5205 | ucontrol->value.enumerated.item[0] = i; | ||
5206 | break; | ||
5207 | } | ||
5208 | } | ||
5209 | return 0; | ||
5210 | } | ||
5211 | EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get); | ||
5212 | |||
5213 | /** | ||
5214 | * snd_hda_ch_mode_put - Put callback helper for the channel mode enum | ||
5215 | * @codec: the HDA codec | ||
5216 | * @ucontrol: pointer to get/store the data | ||
5217 | * @chmode: channel mode array | ||
5218 | * @num_chmodes: channel mode array size | ||
5219 | * @max_channelsp: pointer to store the max channels | ||
5220 | */ | ||
5221 | int snd_hda_ch_mode_put(struct hda_codec *codec, | ||
5222 | struct snd_ctl_elem_value *ucontrol, | ||
5223 | const struct hda_channel_mode *chmode, | ||
5224 | int num_chmodes, | ||
5225 | int *max_channelsp) | ||
5226 | { | ||
5227 | unsigned int mode; | ||
5228 | |||
5229 | mode = ucontrol->value.enumerated.item[0]; | ||
5230 | if (mode >= num_chmodes) | ||
5231 | return -EINVAL; | ||
5232 | if (*max_channelsp == chmode[mode].channels) | ||
5233 | return 0; | ||
5234 | /* change the current channel setting */ | ||
5235 | *max_channelsp = chmode[mode].channels; | ||
5236 | if (chmode[mode].sequence) | ||
5237 | snd_hda_sequence_write_cache(codec, chmode[mode].sequence); | ||
5238 | return 1; | ||
5239 | } | ||
5240 | EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put); | ||
5241 | |||
5242 | /* | ||
5243 | * input MUX helper | 4847 | * input MUX helper |
5244 | */ | 4848 | */ |
5245 | 4849 | ||
@@ -5780,77 +5384,26 @@ int snd_hda_add_imux_item(struct hda_codec *codec, | |||
5780 | } | 5384 | } |
5781 | EXPORT_SYMBOL_GPL(snd_hda_add_imux_item); | 5385 | EXPORT_SYMBOL_GPL(snd_hda_add_imux_item); |
5782 | 5386 | ||
5783 | |||
5784 | #ifdef CONFIG_PM | ||
5785 | /* | ||
5786 | * power management | ||
5787 | */ | ||
5788 | |||
5789 | |||
5790 | static void hda_async_suspend(void *data, async_cookie_t cookie) | ||
5791 | { | ||
5792 | hda_call_codec_suspend(data, false); | ||
5793 | } | ||
5794 | |||
5795 | static void hda_async_resume(void *data, async_cookie_t cookie) | ||
5796 | { | ||
5797 | hda_call_codec_resume(data); | ||
5798 | } | ||
5799 | |||
5800 | /** | 5387 | /** |
5801 | * snd_hda_suspend - suspend the codecs | 5388 | * snd_hda_bus_reset - Reset the bus |
5802 | * @bus: the HDA bus | 5389 | * @bus: HD-audio bus |
5803 | * | ||
5804 | * Returns 0 if successful. | ||
5805 | */ | 5390 | */ |
5806 | int snd_hda_suspend(struct hda_bus *bus) | 5391 | void snd_hda_bus_reset(struct hda_bus *bus) |
5807 | { | 5392 | { |
5808 | struct hda_codec *codec; | 5393 | struct hda_codec *codec; |
5809 | ASYNC_DOMAIN_EXCLUSIVE(domain); | ||
5810 | 5394 | ||
5811 | list_for_each_entry(codec, &bus->codec_list, list) { | 5395 | list_for_each_entry(codec, &bus->codec_list, list) { |
5396 | /* FIXME: maybe a better way needed for forced reset */ | ||
5812 | cancel_delayed_work_sync(&codec->jackpoll_work); | 5397 | cancel_delayed_work_sync(&codec->jackpoll_work); |
5398 | #ifdef CONFIG_PM | ||
5813 | if (hda_codec_is_power_on(codec)) { | 5399 | if (hda_codec_is_power_on(codec)) { |
5814 | if (bus->num_codecs > 1) | 5400 | hda_call_codec_suspend(codec); |
5815 | async_schedule_domain(hda_async_suspend, codec, | ||
5816 | &domain); | ||
5817 | else | ||
5818 | hda_call_codec_suspend(codec, false); | ||
5819 | } | ||
5820 | } | ||
5821 | |||
5822 | if (bus->num_codecs > 1) | ||
5823 | async_synchronize_full_domain(&domain); | ||
5824 | |||
5825 | return 0; | ||
5826 | } | ||
5827 | EXPORT_SYMBOL_GPL(snd_hda_suspend); | ||
5828 | |||
5829 | /** | ||
5830 | * snd_hda_resume - resume the codecs | ||
5831 | * @bus: the HDA bus | ||
5832 | * | ||
5833 | * Returns 0 if successful. | ||
5834 | */ | ||
5835 | int snd_hda_resume(struct hda_bus *bus) | ||
5836 | { | ||
5837 | struct hda_codec *codec; | ||
5838 | ASYNC_DOMAIN_EXCLUSIVE(domain); | ||
5839 | |||
5840 | list_for_each_entry(codec, &bus->codec_list, list) { | ||
5841 | if (bus->num_codecs > 1) | ||
5842 | async_schedule_domain(hda_async_resume, codec, &domain); | ||
5843 | else | ||
5844 | hda_call_codec_resume(codec); | 5401 | hda_call_codec_resume(codec); |
5402 | } | ||
5403 | #endif | ||
5845 | } | 5404 | } |
5846 | |||
5847 | if (bus->num_codecs > 1) | ||
5848 | async_synchronize_full_domain(&domain); | ||
5849 | |||
5850 | return 0; | ||
5851 | } | 5405 | } |
5852 | EXPORT_SYMBOL_GPL(snd_hda_resume); | 5406 | EXPORT_SYMBOL_GPL(snd_hda_bus_reset); |
5853 | #endif /* CONFIG_PM */ | ||
5854 | 5407 | ||
5855 | /* | 5408 | /* |
5856 | * generic arrays | 5409 | * generic arrays |