162810dbdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21835a0f9STakashi Iwai /* 31835a0f9STakashi Iwai * Jack-detection handling for HD-audio 41835a0f9STakashi Iwai * 51835a0f9STakashi Iwai * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> 61835a0f9STakashi Iwai */ 71835a0f9STakashi Iwai 81835a0f9STakashi Iwai #include <linux/init.h> 91835a0f9STakashi Iwai #include <linux/slab.h> 10bf815bf0STakashi Iwai #include <linux/export.h> 111835a0f9STakashi Iwai #include <sound/core.h> 1201a61e12STakashi Iwai #include <sound/control.h> 13aad37dbdSTakashi Iwai #include <sound/jack.h> 14be57bfffSPierre-Louis Bossart #include <sound/hda_codec.h> 151835a0f9STakashi Iwai #include "hda_local.h" 16128bc4baSTakashi Iwai #include "hda_auto_parser.h" 171835a0f9STakashi Iwai #include "hda_jack.h" 181835a0f9STakashi Iwai 1995a962c3STakashi Iwai /** 2095a962c3STakashi Iwai * is_jack_detectable - Check whether the given pin is jack-detectable 2195a962c3STakashi Iwai * @codec: the HDA codec 2295a962c3STakashi Iwai * @nid: pin NID 2395a962c3STakashi Iwai * 2495a962c3STakashi Iwai * Check whether the given pin is capable to report the jack detection. 2595a962c3STakashi Iwai * The jack detection might not work by various reasons, e.g. the jack 2695a962c3STakashi Iwai * detection is prohibited in the codec level, the pin config has 2795a962c3STakashi Iwai * AC_DEFCFG_MISC_NO_PRESENCE bit, no unsol support, etc. 2895a962c3STakashi Iwai */ 29a9c74173STakashi Iwai bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) 30a9c74173STakashi Iwai { 3171b1e9e4STakashi Iwai if (codec->no_jack_detect) 3271b1e9e4STakashi Iwai return false; 33a9c74173STakashi Iwai if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_PRES_DETECT)) 34a9c74173STakashi Iwai return false; 355fe8e1e6SDavid Henningsson if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & 365fe8e1e6SDavid Henningsson AC_DEFCFG_MISC_NO_PRESENCE) 37a9c74173STakashi Iwai return false; 3876a19c69STakashi Iwai if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) && 3976a19c69STakashi Iwai !codec->jackpoll_interval) 40a9c74173STakashi Iwai return false; 41a9c74173STakashi Iwai return true; 42a9c74173STakashi Iwai } 432698ea98STakashi Iwai EXPORT_SYMBOL_GPL(is_jack_detectable); 44a9c74173STakashi Iwai 451835a0f9STakashi Iwai /* execute pin sense measurement */ 465204a05dSNikhil Mahale static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 471835a0f9STakashi Iwai { 481835a0f9STakashi Iwai u32 pincap; 499cc159c6STakashi Iwai u32 val; 501835a0f9STakashi Iwai 511835a0f9STakashi Iwai if (!codec->no_trigger_sense) { 521835a0f9STakashi Iwai pincap = snd_hda_query_pin_caps(codec, nid); 531835a0f9STakashi Iwai if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ 541835a0f9STakashi Iwai snd_hda_codec_read(codec, nid, 0, 551835a0f9STakashi Iwai AC_VERB_SET_PIN_SENSE, 0); 561835a0f9STakashi Iwai } 579cc159c6STakashi Iwai val = snd_hda_codec_read(codec, nid, 0, 585204a05dSNikhil Mahale AC_VERB_GET_PIN_SENSE, dev_id); 599cc159c6STakashi Iwai if (codec->inv_jack_detect) 609cc159c6STakashi Iwai val ^= AC_PINSENSE_PRESENCE; 619cc159c6STakashi Iwai return val; 621835a0f9STakashi Iwai } 631835a0f9STakashi Iwai 641835a0f9STakashi Iwai /** 655204a05dSNikhil Mahale * snd_hda_jack_tbl_get_mst - query the jack-table entry for the given NID 66a11e9b16STakashi Iwai * @codec: the HDA codec 67a11e9b16STakashi Iwai * @nid: pin NID to refer to 685204a05dSNikhil Mahale * @dev_id: pin device entry id 691835a0f9STakashi Iwai */ 701835a0f9STakashi Iwai struct hda_jack_tbl * 715204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id) 725204a05dSNikhil Mahale { 735204a05dSNikhil Mahale struct hda_jack_tbl *jack = codec->jacktbl.list; 745204a05dSNikhil Mahale int i; 755204a05dSNikhil Mahale 765204a05dSNikhil Mahale if (!nid || !jack) 775204a05dSNikhil Mahale return NULL; 785204a05dSNikhil Mahale for (i = 0; i < codec->jacktbl.used; i++, jack++) 795204a05dSNikhil Mahale if (jack->nid == nid && jack->dev_id == dev_id) 805204a05dSNikhil Mahale return jack; 815204a05dSNikhil Mahale return NULL; 825204a05dSNikhil Mahale } 835204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_mst); 845204a05dSNikhil Mahale 855204a05dSNikhil Mahale /** 865204a05dSNikhil Mahale * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag 875204a05dSNikhil Mahale * @codec: the HDA codec 885204a05dSNikhil Mahale * @tag: tag value to refer to 895204a05dSNikhil Mahale * @dev_id: pin device entry id 905204a05dSNikhil Mahale */ 915204a05dSNikhil Mahale struct hda_jack_tbl * 925204a05dSNikhil Mahale snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, 935204a05dSNikhil Mahale unsigned char tag, int dev_id) 945204a05dSNikhil Mahale { 955204a05dSNikhil Mahale struct hda_jack_tbl *jack = codec->jacktbl.list; 965204a05dSNikhil Mahale int i; 975204a05dSNikhil Mahale 985204a05dSNikhil Mahale if (!tag || !jack) 995204a05dSNikhil Mahale return NULL; 1005204a05dSNikhil Mahale for (i = 0; i < codec->jacktbl.used; i++, jack++) 1015204a05dSNikhil Mahale if (jack->tag == tag && jack->dev_id == dev_id) 1025204a05dSNikhil Mahale return jack; 1035204a05dSNikhil Mahale return NULL; 1045204a05dSNikhil Mahale } 1055204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); 1065204a05dSNikhil Mahale 1075204a05dSNikhil Mahale static struct hda_jack_tbl * 1085204a05dSNikhil Mahale any_jack_tbl_get_from_nid(struct hda_codec *codec, hda_nid_t nid) 1091835a0f9STakashi Iwai { 1101835a0f9STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 1111835a0f9STakashi Iwai int i; 1121835a0f9STakashi Iwai 1131835a0f9STakashi Iwai if (!nid || !jack) 1141835a0f9STakashi Iwai return NULL; 1151835a0f9STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 1161835a0f9STakashi Iwai if (jack->nid == nid) 1171835a0f9STakashi Iwai return jack; 1181835a0f9STakashi Iwai return NULL; 1191835a0f9STakashi Iwai } 1203a93897eSTakashi Iwai 1213a93897eSTakashi Iwai /** 1221835a0f9STakashi Iwai * snd_hda_jack_tbl_new - create a jack-table entry for the given NID 123a11e9b16STakashi Iwai * @codec: the HDA codec 124a11e9b16STakashi Iwai * @nid: pin NID to assign 1254f5c2653SPierre-Louis Bossart * @dev_id: pin device entry id 1261835a0f9STakashi Iwai */ 12781965f1fSTakashi Iwai static struct hda_jack_tbl * 1285204a05dSNikhil Mahale snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid, int dev_id) 1291835a0f9STakashi Iwai { 1305204a05dSNikhil Mahale struct hda_jack_tbl *jack = 1315204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 1325204a05dSNikhil Mahale struct hda_jack_tbl *existing_nid_jack = 1335204a05dSNikhil Mahale any_jack_tbl_get_from_nid(codec, nid); 1345204a05dSNikhil Mahale 1355204a05dSNikhil Mahale WARN_ON(dev_id != 0 && !codec->dp_mst); 1365204a05dSNikhil Mahale 1371835a0f9STakashi Iwai if (jack) 1381835a0f9STakashi Iwai return jack; 1391835a0f9STakashi Iwai jack = snd_array_new(&codec->jacktbl); 1401835a0f9STakashi Iwai if (!jack) 1411835a0f9STakashi Iwai return NULL; 1421835a0f9STakashi Iwai jack->nid = nid; 1435204a05dSNikhil Mahale jack->dev_id = dev_id; 1441835a0f9STakashi Iwai jack->jack_dirty = 1; 1455204a05dSNikhil Mahale if (existing_nid_jack) { 1465204a05dSNikhil Mahale jack->tag = existing_nid_jack->tag; 1475204a05dSNikhil Mahale 1485204a05dSNikhil Mahale /* 1495204a05dSNikhil Mahale * Copy jack_detect from existing_nid_jack to avoid 1505204a05dSNikhil Mahale * snd_hda_jack_detect_enable_callback_mst() making multiple 1515204a05dSNikhil Mahale * SET_UNSOLICITED_ENABLE calls on the same pin. 1525204a05dSNikhil Mahale */ 1535204a05dSNikhil Mahale jack->jack_detect = existing_nid_jack->jack_detect; 1545204a05dSNikhil Mahale } else { 1553a93897eSTakashi Iwai jack->tag = codec->jacktbl.used; 1565204a05dSNikhil Mahale } 1575204a05dSNikhil Mahale 1581835a0f9STakashi Iwai return jack; 1591835a0f9STakashi Iwai } 1601835a0f9STakashi Iwai 1611835a0f9STakashi Iwai void snd_hda_jack_tbl_clear(struct hda_codec *codec) 1621835a0f9STakashi Iwai { 16331ef2257STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 16431ef2257STakashi Iwai int i; 1651a4f69d5STakashi Iwai 16631ef2257STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) { 1671a4f69d5STakashi Iwai struct hda_jack_callback *cb, *next; 1682ba2dfa1SJie Yang 1691a4f69d5STakashi Iwai /* free jack instances manually when clearing/reconfiguring */ 1701a4f69d5STakashi Iwai if (!codec->bus->shutdown && jack->jack) 1716efdd851STakashi Iwai snd_device_free(codec->card, jack->jack); 1722ba2dfa1SJie Yang 1731a4f69d5STakashi Iwai for (cb = jack->callback; cb; cb = next) { 1741a4f69d5STakashi Iwai next = cb->next; 1751a4f69d5STakashi Iwai kfree(cb); 1761a4f69d5STakashi Iwai } 1771a4f69d5STakashi Iwai } 1781835a0f9STakashi Iwai snd_array_free(&codec->jacktbl); 1791835a0f9STakashi Iwai } 1801835a0f9STakashi Iwai 1810619ba8cSDylan Reid #define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) 1820619ba8cSDylan Reid 1831835a0f9STakashi Iwai /* update the cached value and notification flag if needed */ 1841835a0f9STakashi Iwai static void jack_detect_update(struct hda_codec *codec, 1851835a0f9STakashi Iwai struct hda_jack_tbl *jack) 1861835a0f9STakashi Iwai { 18780c8bfbeSDavid Henningsson if (!jack->jack_dirty) 18880c8bfbeSDavid Henningsson return; 18980c8bfbeSDavid Henningsson 19080c8bfbeSDavid Henningsson if (jack->phantom_jack) 19180c8bfbeSDavid Henningsson jack->pin_sense = AC_PINSENSE_PRESENCE; 19280c8bfbeSDavid Henningsson else 1935204a05dSNikhil Mahale jack->pin_sense = read_pin_sense(codec, jack->nid, 1945204a05dSNikhil Mahale jack->dev_id); 19580c8bfbeSDavid Henningsson 1960619ba8cSDylan Reid /* A gating jack indicates the jack is invalid if gating is unplugged */ 1975204a05dSNikhil Mahale if (jack->gating_jack && 1985204a05dSNikhil Mahale !snd_hda_jack_detect_mst(codec, jack->gating_jack, jack->dev_id)) 1990619ba8cSDylan Reid jack->pin_sense &= ~AC_PINSENSE_PRESENCE; 2000619ba8cSDylan Reid 2011835a0f9STakashi Iwai jack->jack_dirty = 0; 2020619ba8cSDylan Reid 2030619ba8cSDylan Reid /* If a jack is gated by this one update it. */ 2040619ba8cSDylan Reid if (jack->gated_jack) { 2050619ba8cSDylan Reid struct hda_jack_tbl *gated = 2065204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 2075204a05dSNikhil Mahale jack->dev_id); 2080619ba8cSDylan Reid if (gated) { 2090619ba8cSDylan Reid gated->jack_dirty = 1; 2100619ba8cSDylan Reid jack_detect_update(codec, gated); 2110619ba8cSDylan Reid } 2120619ba8cSDylan Reid } 2131835a0f9STakashi Iwai } 2141835a0f9STakashi Iwai 2151835a0f9STakashi Iwai /** 2161835a0f9STakashi Iwai * snd_hda_set_dirty_all - Mark all the cached as dirty 217a11e9b16STakashi Iwai * @codec: the HDA codec 2181835a0f9STakashi Iwai * 2191835a0f9STakashi Iwai * This function sets the dirty flag to all entries of jack table. 2201835a0f9STakashi Iwai * It's called from the resume path in hda_codec.c. 2211835a0f9STakashi Iwai */ 2221835a0f9STakashi Iwai void snd_hda_jack_set_dirty_all(struct hda_codec *codec) 2231835a0f9STakashi Iwai { 2241835a0f9STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 2251835a0f9STakashi Iwai int i; 2261835a0f9STakashi Iwai 2271835a0f9STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 2281835a0f9STakashi Iwai if (jack->nid) 2291835a0f9STakashi Iwai jack->jack_dirty = 1; 2301835a0f9STakashi Iwai } 2312698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); 2321835a0f9STakashi Iwai 2331835a0f9STakashi Iwai /** 23480b917a8SNikhil Mahale * snd_hda_jack_pin_sense - execute pin sense measurement 2351835a0f9STakashi Iwai * @codec: the CODEC to sense 2361835a0f9STakashi Iwai * @nid: the pin NID to sense 2374f5c2653SPierre-Louis Bossart * @dev_id: pin device entry id 2381835a0f9STakashi Iwai * 2391835a0f9STakashi Iwai * Execute necessary pin sense measurement and return its Presence Detect, 2401835a0f9STakashi Iwai * Impedance, ELD Valid etc. status bits. 2411835a0f9STakashi Iwai */ 2425204a05dSNikhil Mahale u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 2431835a0f9STakashi Iwai { 2445204a05dSNikhil Mahale struct hda_jack_tbl *jack = 2455204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 2461835a0f9STakashi Iwai if (jack) { 2471835a0f9STakashi Iwai jack_detect_update(codec, jack); 2481835a0f9STakashi Iwai return jack->pin_sense; 2491835a0f9STakashi Iwai } 2505204a05dSNikhil Mahale return read_pin_sense(codec, nid, dev_id); 2511835a0f9STakashi Iwai } 25280b917a8SNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); 2531835a0f9STakashi Iwai 2541835a0f9STakashi Iwai /** 2555204a05dSNikhil Mahale * snd_hda_jack_detect_state_mst - query pin Presence Detect status 2561835a0f9STakashi Iwai * @codec: the CODEC to sense 2571835a0f9STakashi Iwai * @nid: the pin NID to sense 2585204a05dSNikhil Mahale * @dev_id: pin device entry id 2591835a0f9STakashi Iwai * 26060ea8ca2STakashi Iwai * Query and return the pin's Presence Detect status, as either 26160ea8ca2STakashi Iwai * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. 2621835a0f9STakashi Iwai */ 2635204a05dSNikhil Mahale int snd_hda_jack_detect_state_mst(struct hda_codec *codec, 2645204a05dSNikhil Mahale hda_nid_t nid, int dev_id) 2651835a0f9STakashi Iwai { 2665204a05dSNikhil Mahale struct hda_jack_tbl *jack = 2675204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 26860ea8ca2STakashi Iwai if (jack && jack->phantom_jack) 26960ea8ca2STakashi Iwai return HDA_JACK_PHANTOM; 2705204a05dSNikhil Mahale else if (snd_hda_jack_pin_sense(codec, nid, dev_id) & 2715204a05dSNikhil Mahale AC_PINSENSE_PRESENCE) 27260ea8ca2STakashi Iwai return HDA_JACK_PRESENT; 27360ea8ca2STakashi Iwai else 27460ea8ca2STakashi Iwai return HDA_JACK_NOT_PRESENT; 2751835a0f9STakashi Iwai } 2765204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); 2771835a0f9STakashi Iwai 278*f4794c60SHui Wang static bool func_is_already_in_callback_list(struct hda_jack_tbl *jack, 279*f4794c60SHui Wang hda_jack_callback_fn func) 280*f4794c60SHui Wang { 281*f4794c60SHui Wang struct hda_jack_callback *cb; 282*f4794c60SHui Wang 283*f4794c60SHui Wang for (cb = jack->callback; cb; cb = cb->next) { 284*f4794c60SHui Wang if (cb->func == func) 285*f4794c60SHui Wang return true; 286*f4794c60SHui Wang } 287*f4794c60SHui Wang return false; 288*f4794c60SHui Wang } 289*f4794c60SHui Wang 2901835a0f9STakashi Iwai /** 2915204a05dSNikhil Mahale * snd_hda_jack_detect_enable_mst - enable the jack-detection 292a11e9b16STakashi Iwai * @codec: the HDA codec 293a11e9b16STakashi Iwai * @nid: pin NID to enable 294a11e9b16STakashi Iwai * @func: callback function to register 2955204a05dSNikhil Mahale * @dev_id: pin device entry id 296bda17b82STakashi Iwai * 297bda17b82STakashi Iwai * In the case of error, the return value will be a pointer embedded with 298bda17b82STakashi Iwai * errno. Check and handle the return value appropriately with standard 299bda17b82STakashi Iwai * macros such as @IS_ERR() and @PTR_ERR(). 3001835a0f9STakashi Iwai */ 3011a4f69d5STakashi Iwai struct hda_jack_callback * 3025204a05dSNikhil Mahale snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, 3035204a05dSNikhil Mahale int dev_id, hda_jack_callback_fn func) 3041835a0f9STakashi Iwai { 3051a4f69d5STakashi Iwai struct hda_jack_tbl *jack; 3061a4f69d5STakashi Iwai struct hda_jack_callback *callback = NULL; 307bda17b82STakashi Iwai int err; 308bda17b82STakashi Iwai 3095204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 3101835a0f9STakashi Iwai if (!jack) 311bda17b82STakashi Iwai return ERR_PTR(-ENOMEM); 312*f4794c60SHui Wang if (func && !func_is_already_in_callback_list(jack, func)) { 3131a4f69d5STakashi Iwai callback = kzalloc(sizeof(*callback), GFP_KERNEL); 3141a4f69d5STakashi Iwai if (!callback) 3151a4f69d5STakashi Iwai return ERR_PTR(-ENOMEM); 3161a4f69d5STakashi Iwai callback->func = func; 3172ebab40eSTakashi Iwai callback->nid = jack->nid; 3185204a05dSNikhil Mahale callback->dev_id = jack->dev_id; 3191a4f69d5STakashi Iwai callback->next = jack->callback; 3201a4f69d5STakashi Iwai jack->callback = callback; 3211a4f69d5STakashi Iwai } 3221a4f69d5STakashi Iwai 3233a93897eSTakashi Iwai if (jack->jack_detect) 3241a4f69d5STakashi Iwai return callback; /* already registered */ 3253a93897eSTakashi Iwai jack->jack_detect = 1; 32634a93187SDavid Henningsson if (codec->jackpoll_interval > 0) 3271a4f69d5STakashi Iwai return callback; /* No unsol if we're polling instead */ 328bda17b82STakashi Iwai err = snd_hda_codec_write_cache(codec, nid, 0, 3291835a0f9STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 3303a93897eSTakashi Iwai AC_USRSP_EN | jack->tag); 331bda17b82STakashi Iwai if (err < 0) 332bda17b82STakashi Iwai return ERR_PTR(err); 3331a4f69d5STakashi Iwai return callback; 3341835a0f9STakashi Iwai } 3355204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst); 336954df2a9SDavid Henningsson 33795a962c3STakashi Iwai /** 33895a962c3STakashi Iwai * snd_hda_jack_detect_enable - Enable the jack detection on the given pin 33995a962c3STakashi Iwai * @codec: the HDA codec 34095a962c3STakashi Iwai * @nid: pin NID to enable jack detection 3415204a05dSNikhil Mahale * @dev_id: pin device entry id 34295a962c3STakashi Iwai * 34395a962c3STakashi Iwai * Enable the jack detection with the default callback. Returns zero if 34495a962c3STakashi Iwai * successful or a negative error code. 34595a962c3STakashi Iwai */ 3465204a05dSNikhil Mahale int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, 3475204a05dSNikhil Mahale int dev_id) 348954df2a9SDavid Henningsson { 3495204a05dSNikhil Mahale return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback_mst(codec, 3505204a05dSNikhil Mahale nid, 3515204a05dSNikhil Mahale dev_id, 3525204a05dSNikhil Mahale NULL)); 353954df2a9SDavid Henningsson } 3542698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); 35501a61e12STakashi Iwai 35601a61e12STakashi Iwai /** 3570619ba8cSDylan Reid * snd_hda_jack_set_gating_jack - Set gating jack. 358a11e9b16STakashi Iwai * @codec: the HDA codec 359a11e9b16STakashi Iwai * @gated_nid: gated pin NID 360a11e9b16STakashi Iwai * @gating_nid: gating pin NID 3610619ba8cSDylan Reid * 3620619ba8cSDylan Reid * Indicates the gated jack is only valid when the gating jack is plugged. 3630619ba8cSDylan Reid */ 3640619ba8cSDylan Reid int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, 3650619ba8cSDylan Reid hda_nid_t gating_nid) 3660619ba8cSDylan Reid { 3675204a05dSNikhil Mahale struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0); 3685204a05dSNikhil Mahale struct hda_jack_tbl *gating = 3695204a05dSNikhil Mahale snd_hda_jack_tbl_new(codec, gating_nid, 0); 3705204a05dSNikhil Mahale 3715204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 3720619ba8cSDylan Reid 3730619ba8cSDylan Reid if (!gated || !gating) 3740619ba8cSDylan Reid return -EINVAL; 3750619ba8cSDylan Reid 3760619ba8cSDylan Reid gated->gating_jack = gating_nid; 3770619ba8cSDylan Reid gating->gated_jack = gated_nid; 3780619ba8cSDylan Reid 3790619ba8cSDylan Reid return 0; 3800619ba8cSDylan Reid } 3812698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); 3820619ba8cSDylan Reid 3830619ba8cSDylan Reid /** 38401a61e12STakashi Iwai * snd_hda_jack_report_sync - sync the states of all jacks and report if changed 385a11e9b16STakashi Iwai * @codec: the HDA codec 38601a61e12STakashi Iwai */ 38701a61e12STakashi Iwai void snd_hda_jack_report_sync(struct hda_codec *codec) 38801a61e12STakashi Iwai { 3890619ba8cSDylan Reid struct hda_jack_tbl *jack; 39035be544aSTakashi Iwai int i, state; 39101a61e12STakashi Iwai 3920619ba8cSDylan Reid /* update all jacks at first */ 3930619ba8cSDylan Reid jack = codec->jacktbl.list; 3940619ba8cSDylan Reid for (i = 0; i < codec->jacktbl.used; i++, jack++) 3950619ba8cSDylan Reid if (jack->nid) 3960619ba8cSDylan Reid jack_detect_update(codec, jack); 3970619ba8cSDylan Reid 3980619ba8cSDylan Reid /* report the updated jacks; it's done after updating all jacks 3990619ba8cSDylan Reid * to make sure that all gating jacks properly have been set 4000619ba8cSDylan Reid */ 4010619ba8cSDylan Reid jack = codec->jacktbl.list; 40201a61e12STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 40301a61e12STakashi Iwai if (jack->nid) { 4042ba2dfa1SJie Yang if (!jack->jack || jack->block_report) 405cfc7c9d3STakashi Iwai continue; 406911761c2STakashi Iwai state = jack->button_state; 407911761c2STakashi Iwai if (get_jack_plug_state(jack->pin_sense)) 408911761c2STakashi Iwai state |= jack->type; 409911761c2STakashi Iwai snd_jack_report(jack->jack, state); 410911761c2STakashi Iwai if (jack->button_state) { 41131ef2257STakashi Iwai snd_jack_report(jack->jack, 412911761c2STakashi Iwai state & ~jack->button_state); 413911761c2STakashi Iwai jack->button_state = 0; /* button released */ 414911761c2STakashi Iwai } 41501a61e12STakashi Iwai } 41601a61e12STakashi Iwai } 4172698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); 41801a61e12STakashi Iwai 41931ef2257STakashi Iwai /* guess the jack type from the pin-config */ 42031ef2257STakashi Iwai static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) 42131ef2257STakashi Iwai { 42231ef2257STakashi Iwai unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 42331ef2257STakashi Iwai switch (get_defcfg_device(def_conf)) { 42431ef2257STakashi Iwai case AC_JACK_LINE_OUT: 42531ef2257STakashi Iwai case AC_JACK_SPEAKER: 42631ef2257STakashi Iwai return SND_JACK_LINEOUT; 42731ef2257STakashi Iwai case AC_JACK_HP_OUT: 42831ef2257STakashi Iwai return SND_JACK_HEADPHONE; 42931ef2257STakashi Iwai case AC_JACK_SPDIF_OUT: 43031ef2257STakashi Iwai case AC_JACK_DIG_OTHER_OUT: 43131ef2257STakashi Iwai return SND_JACK_AVOUT; 43231ef2257STakashi Iwai case AC_JACK_MIC_IN: 43331ef2257STakashi Iwai return SND_JACK_MICROPHONE; 43431ef2257STakashi Iwai default: 43531ef2257STakashi Iwai return SND_JACK_LINEIN; 43631ef2257STakashi Iwai } 43731ef2257STakashi Iwai } 43831ef2257STakashi Iwai 43931ef2257STakashi Iwai static void hda_free_jack_priv(struct snd_jack *jack) 44031ef2257STakashi Iwai { 44131ef2257STakashi Iwai struct hda_jack_tbl *jacks = jack->private_data; 44231ef2257STakashi Iwai jacks->nid = 0; 44331ef2257STakashi Iwai jacks->jack = NULL; 44431ef2257STakashi Iwai } 44531ef2257STakashi Iwai 44601a61e12STakashi Iwai /** 4475204a05dSNikhil Mahale * snd_hda_jack_add_kctl_mst - Add a kctl for the given pin 448a11e9b16STakashi Iwai * @codec: the HDA codec 449a11e9b16STakashi Iwai * @nid: pin NID to assign 4505204a05dSNikhil Mahale * @dev_id : pin device entry id 451a11e9b16STakashi Iwai * @name: string name for the jack 452a11e9b16STakashi Iwai * @phantom_jack: flag to deal as a phantom jack 453911761c2STakashi Iwai * @type: jack type bits to be reported, 0 for guessing from pincfg 454911761c2STakashi Iwai * @keymap: optional jack / key mapping 45501a61e12STakashi Iwai * 45601a61e12STakashi Iwai * This assigns a jack-detection kctl to the given pin. The kcontrol 45701a61e12STakashi Iwai * will have the given name and index. 45801a61e12STakashi Iwai */ 4595204a05dSNikhil Mahale int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, 4605204a05dSNikhil Mahale int dev_id, const char *name, bool phantom_jack, 461911761c2STakashi Iwai int type, const struct hda_jack_keymap *keymap) 46201a61e12STakashi Iwai { 46301a61e12STakashi Iwai struct hda_jack_tbl *jack; 464911761c2STakashi Iwai const struct hda_jack_keymap *map; 465911761c2STakashi Iwai int err, state, buttons; 46601a61e12STakashi Iwai 4675204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 46801a61e12STakashi Iwai if (!jack) 46901a61e12STakashi Iwai return 0; 4702ba2dfa1SJie Yang if (jack->jack) 47101a61e12STakashi Iwai return 0; /* already created */ 47280c8bfbeSDavid Henningsson 473911761c2STakashi Iwai if (!type) 4742ba2dfa1SJie Yang type = get_input_jack_type(codec, nid); 475911761c2STakashi Iwai 476911761c2STakashi Iwai buttons = 0; 477911761c2STakashi Iwai if (keymap) { 478911761c2STakashi Iwai for (map = keymap; map->type; map++) 479911761c2STakashi Iwai buttons |= map->type; 480911761c2STakashi Iwai } 481911761c2STakashi Iwai 482911761c2STakashi Iwai err = snd_jack_new(codec->card, name, type | buttons, 4832ba2dfa1SJie Yang &jack->jack, true, phantom_jack); 48431ef2257STakashi Iwai if (err < 0) 48531ef2257STakashi Iwai return err; 4862ba2dfa1SJie Yang 4872ba2dfa1SJie Yang jack->phantom_jack = !!phantom_jack; 4882ba2dfa1SJie Yang jack->type = type; 489911761c2STakashi Iwai jack->button_state = 0; 49031ef2257STakashi Iwai jack->jack->private_data = jack; 49131ef2257STakashi Iwai jack->jack->private_free = hda_free_jack_priv; 492911761c2STakashi Iwai if (keymap) { 493911761c2STakashi Iwai for (map = keymap; map->type; map++) 494911761c2STakashi Iwai snd_jack_set_key(jack->jack, map->type, map->key); 495911761c2STakashi Iwai } 496911761c2STakashi Iwai 4975204a05dSNikhil Mahale state = snd_hda_jack_detect_mst(codec, nid, dev_id); 49831ef2257STakashi Iwai snd_jack_report(jack->jack, state ? jack->type : 0); 4992ba2dfa1SJie Yang 50001a61e12STakashi Iwai return 0; 50101a61e12STakashi Iwai } 5025204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst); 50301a61e12STakashi Iwai 504201e06ffSTakashi Iwai static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, 505b26b5116SDavid Henningsson const struct auto_pin_cfg *cfg, 506b26b5116SDavid Henningsson const char *base_name) 50701a61e12STakashi Iwai { 5083a93897eSTakashi Iwai unsigned int def_conf, conn; 509975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 5102ba2dfa1SJie Yang int err; 51180c8bfbeSDavid Henningsson bool phantom_jack; 5123a93897eSTakashi Iwai 5135204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 5145204a05dSNikhil Mahale 51501a61e12STakashi Iwai if (!nid) 51601a61e12STakashi Iwai return 0; 5173a93897eSTakashi Iwai def_conf = snd_hda_codec_get_pincfg(codec, nid); 5183a93897eSTakashi Iwai conn = get_defcfg_connect(def_conf); 51980c8bfbeSDavid Henningsson if (conn == AC_JACK_PORT_NONE) 5203a93897eSTakashi Iwai return 0; 52180c8bfbeSDavid Henningsson phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || 52280c8bfbeSDavid Henningsson !is_jack_detectable(codec, nid); 5233a93897eSTakashi Iwai 5242ba2dfa1SJie Yang if (base_name) 525b26b5116SDavid Henningsson strlcpy(name, base_name, sizeof(name)); 5262ba2dfa1SJie Yang else 5272ba2dfa1SJie Yang snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); 52880c8bfbeSDavid Henningsson if (phantom_jack) 52980c8bfbeSDavid Henningsson /* Example final name: "Internal Mic Phantom Jack" */ 53080c8bfbeSDavid Henningsson strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); 531911761c2STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); 5323a93897eSTakashi Iwai if (err < 0) 5333a93897eSTakashi Iwai return err; 53480c8bfbeSDavid Henningsson 53580c8bfbeSDavid Henningsson if (!phantom_jack) 5365204a05dSNikhil Mahale return snd_hda_jack_detect_enable(codec, nid, 0); 53780c8bfbeSDavid Henningsson return 0; 53801a61e12STakashi Iwai } 53901a61e12STakashi Iwai 54001a61e12STakashi Iwai /** 54101a61e12STakashi Iwai * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg 542a11e9b16STakashi Iwai * @codec: the HDA codec 543a11e9b16STakashi Iwai * @cfg: pin config table to parse 54401a61e12STakashi Iwai */ 54501a61e12STakashi Iwai int snd_hda_jack_add_kctls(struct hda_codec *codec, 54601a61e12STakashi Iwai const struct auto_pin_cfg *cfg) 54701a61e12STakashi Iwai { 54801a61e12STakashi Iwai const hda_nid_t *p; 549f46c3296STakashi Iwai int i, err; 55001a61e12STakashi Iwai 551b26b5116SDavid Henningsson for (i = 0; i < cfg->num_inputs; i++) { 552b26b5116SDavid Henningsson /* If we have headphone mics; make sure they get the right name 553b26b5116SDavid Henningsson before grabbed by output pins */ 554b26b5116SDavid Henningsson if (cfg->inputs[i].is_headphone_mic) { 555b26b5116SDavid Henningsson if (auto_cfg_hp_outs(cfg) == 1) 556b26b5116SDavid Henningsson err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0], 557b26b5116SDavid Henningsson cfg, "Headphone Mic"); 558b26b5116SDavid Henningsson else 559b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, 560b26b5116SDavid Henningsson cfg, "Headphone Mic"); 561b26b5116SDavid Henningsson } else 562b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, 563b26b5116SDavid Henningsson NULL); 564b26b5116SDavid Henningsson if (err < 0) 565b26b5116SDavid Henningsson return err; 566b26b5116SDavid Henningsson } 567b26b5116SDavid Henningsson 56801a61e12STakashi Iwai for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { 569b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 57001a61e12STakashi Iwai if (err < 0) 57101a61e12STakashi Iwai return err; 57201a61e12STakashi Iwai } 57301a61e12STakashi Iwai for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { 57401a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 57501a61e12STakashi Iwai break; 576b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 57701a61e12STakashi Iwai if (err < 0) 57801a61e12STakashi Iwai return err; 57901a61e12STakashi Iwai } 58001a61e12STakashi Iwai for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { 58101a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 58201a61e12STakashi Iwai break; 583b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 58401a61e12STakashi Iwai if (err < 0) 58501a61e12STakashi Iwai return err; 58601a61e12STakashi Iwai } 58701a61e12STakashi Iwai for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { 588b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 58901a61e12STakashi Iwai if (err < 0) 59001a61e12STakashi Iwai return err; 59101a61e12STakashi Iwai } 592b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL); 59301a61e12STakashi Iwai if (err < 0) 59401a61e12STakashi Iwai return err; 595b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL); 59601a61e12STakashi Iwai if (err < 0) 59701a61e12STakashi Iwai return err; 59801a61e12STakashi Iwai return 0; 59901a61e12STakashi Iwai } 6002698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); 601954df2a9SDavid Henningsson 602e6ce180fSTakashi Iwai static void call_jack_callback(struct hda_codec *codec, unsigned int res, 6030619ba8cSDylan Reid struct hda_jack_tbl *jack) 6040619ba8cSDylan Reid { 6051a4f69d5STakashi Iwai struct hda_jack_callback *cb; 6061a4f69d5STakashi Iwai 607e6ce180fSTakashi Iwai for (cb = jack->callback; cb; cb = cb->next) { 608e6ce180fSTakashi Iwai cb->jack = jack; 609e6ce180fSTakashi Iwai cb->unsol_res = res; 6101a4f69d5STakashi Iwai cb->func(codec, cb); 611e6ce180fSTakashi Iwai } 6120619ba8cSDylan Reid if (jack->gated_jack) { 6130619ba8cSDylan Reid struct hda_jack_tbl *gated = 6145204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 6155204a05dSNikhil Mahale jack->dev_id); 6161a4f69d5STakashi Iwai if (gated) { 617e6ce180fSTakashi Iwai for (cb = gated->callback; cb; cb = cb->next) { 618e6ce180fSTakashi Iwai cb->jack = gated; 619e6ce180fSTakashi Iwai cb->unsol_res = res; 6201a4f69d5STakashi Iwai cb->func(codec, cb); 6211a4f69d5STakashi Iwai } 6220619ba8cSDylan Reid } 6230619ba8cSDylan Reid } 624e6ce180fSTakashi Iwai } 6250619ba8cSDylan Reid 62695a962c3STakashi Iwai /** 62795a962c3STakashi Iwai * snd_hda_jack_unsol_event - Handle an unsolicited event 62895a962c3STakashi Iwai * @codec: the HDA codec 62995a962c3STakashi Iwai * @res: the unsolicited event data 63095a962c3STakashi Iwai */ 631954df2a9SDavid Henningsson void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) 632954df2a9SDavid Henningsson { 633954df2a9SDavid Henningsson struct hda_jack_tbl *event; 634c7e68a69SGuennadi Liakhovetski int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; 635954df2a9SDavid Henningsson 6365204a05dSNikhil Mahale if (codec->dp_mst) { 6375204a05dSNikhil Mahale int dev_entry = 6385204a05dSNikhil Mahale (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; 6395204a05dSNikhil Mahale 6405204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); 6415204a05dSNikhil Mahale } else { 6425204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); 6435204a05dSNikhil Mahale } 644954df2a9SDavid Henningsson if (!event) 645954df2a9SDavid Henningsson return; 646954df2a9SDavid Henningsson event->jack_dirty = 1; 647954df2a9SDavid Henningsson 648e6ce180fSTakashi Iwai call_jack_callback(codec, res, event); 649954df2a9SDavid Henningsson snd_hda_jack_report_sync(codec); 650954df2a9SDavid Henningsson } 6512698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); 652954df2a9SDavid Henningsson 65395a962c3STakashi Iwai /** 65495a962c3STakashi Iwai * snd_hda_jack_poll_all - Poll all jacks 65595a962c3STakashi Iwai * @codec: the HDA codec 65695a962c3STakashi Iwai * 65795a962c3STakashi Iwai * Poll all detectable jacks with dirty flag, update the status, call 65895a962c3STakashi Iwai * callbacks and call snd_hda_jack_report_sync() if any changes are found. 65995a962c3STakashi Iwai */ 66026a6cb6cSDavid Henningsson void snd_hda_jack_poll_all(struct hda_codec *codec) 66126a6cb6cSDavid Henningsson { 66226a6cb6cSDavid Henningsson struct hda_jack_tbl *jack = codec->jacktbl.list; 66326a6cb6cSDavid Henningsson int i, changes = 0; 66426a6cb6cSDavid Henningsson 66526a6cb6cSDavid Henningsson for (i = 0; i < codec->jacktbl.used; i++, jack++) { 66626a6cb6cSDavid Henningsson unsigned int old_sense; 66726a6cb6cSDavid Henningsson if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) 66826a6cb6cSDavid Henningsson continue; 66926a6cb6cSDavid Henningsson old_sense = get_jack_plug_state(jack->pin_sense); 67026a6cb6cSDavid Henningsson jack_detect_update(codec, jack); 67126a6cb6cSDavid Henningsson if (old_sense == get_jack_plug_state(jack->pin_sense)) 67226a6cb6cSDavid Henningsson continue; 67326a6cb6cSDavid Henningsson changes = 1; 674e6ce180fSTakashi Iwai call_jack_callback(codec, 0, jack); 67526a6cb6cSDavid Henningsson } 67626a6cb6cSDavid Henningsson if (changes) 67726a6cb6cSDavid Henningsson snd_hda_jack_report_sync(codec); 67826a6cb6cSDavid Henningsson } 6792698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_poll_all); 68026a6cb6cSDavid Henningsson 681