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 125*4f5c2653SPierre-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 237*4f5c2653SPierre-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 2781835a0f9STakashi Iwai /** 2795204a05dSNikhil Mahale * snd_hda_jack_detect_enable_mst - enable the jack-detection 280a11e9b16STakashi Iwai * @codec: the HDA codec 281a11e9b16STakashi Iwai * @nid: pin NID to enable 282a11e9b16STakashi Iwai * @func: callback function to register 2835204a05dSNikhil Mahale * @dev_id: pin device entry id 284bda17b82STakashi Iwai * 285bda17b82STakashi Iwai * In the case of error, the return value will be a pointer embedded with 286bda17b82STakashi Iwai * errno. Check and handle the return value appropriately with standard 287bda17b82STakashi Iwai * macros such as @IS_ERR() and @PTR_ERR(). 2881835a0f9STakashi Iwai */ 2891a4f69d5STakashi Iwai struct hda_jack_callback * 2905204a05dSNikhil Mahale snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, 2915204a05dSNikhil Mahale int dev_id, hda_jack_callback_fn func) 2921835a0f9STakashi Iwai { 2931a4f69d5STakashi Iwai struct hda_jack_tbl *jack; 2941a4f69d5STakashi Iwai struct hda_jack_callback *callback = NULL; 295bda17b82STakashi Iwai int err; 296bda17b82STakashi Iwai 2975204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 2981835a0f9STakashi Iwai if (!jack) 299bda17b82STakashi Iwai return ERR_PTR(-ENOMEM); 3001a4f69d5STakashi Iwai if (func) { 3011a4f69d5STakashi Iwai callback = kzalloc(sizeof(*callback), GFP_KERNEL); 3021a4f69d5STakashi Iwai if (!callback) 3031a4f69d5STakashi Iwai return ERR_PTR(-ENOMEM); 3041a4f69d5STakashi Iwai callback->func = func; 3052ebab40eSTakashi Iwai callback->nid = jack->nid; 3065204a05dSNikhil Mahale callback->dev_id = jack->dev_id; 3071a4f69d5STakashi Iwai callback->next = jack->callback; 3081a4f69d5STakashi Iwai jack->callback = callback; 3091a4f69d5STakashi Iwai } 3101a4f69d5STakashi Iwai 3113a93897eSTakashi Iwai if (jack->jack_detect) 3121a4f69d5STakashi Iwai return callback; /* already registered */ 3133a93897eSTakashi Iwai jack->jack_detect = 1; 31434a93187SDavid Henningsson if (codec->jackpoll_interval > 0) 3151a4f69d5STakashi Iwai return callback; /* No unsol if we're polling instead */ 316bda17b82STakashi Iwai err = snd_hda_codec_write_cache(codec, nid, 0, 3171835a0f9STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 3183a93897eSTakashi Iwai AC_USRSP_EN | jack->tag); 319bda17b82STakashi Iwai if (err < 0) 320bda17b82STakashi Iwai return ERR_PTR(err); 3211a4f69d5STakashi Iwai return callback; 3221835a0f9STakashi Iwai } 3235204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst); 324954df2a9SDavid Henningsson 32595a962c3STakashi Iwai /** 32695a962c3STakashi Iwai * snd_hda_jack_detect_enable - Enable the jack detection on the given pin 32795a962c3STakashi Iwai * @codec: the HDA codec 32895a962c3STakashi Iwai * @nid: pin NID to enable jack detection 3295204a05dSNikhil Mahale * @dev_id: pin device entry id 33095a962c3STakashi Iwai * 33195a962c3STakashi Iwai * Enable the jack detection with the default callback. Returns zero if 33295a962c3STakashi Iwai * successful or a negative error code. 33395a962c3STakashi Iwai */ 3345204a05dSNikhil Mahale int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, 3355204a05dSNikhil Mahale int dev_id) 336954df2a9SDavid Henningsson { 3375204a05dSNikhil Mahale return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback_mst(codec, 3385204a05dSNikhil Mahale nid, 3395204a05dSNikhil Mahale dev_id, 3405204a05dSNikhil Mahale NULL)); 341954df2a9SDavid Henningsson } 3422698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); 34301a61e12STakashi Iwai 34401a61e12STakashi Iwai /** 3450619ba8cSDylan Reid * snd_hda_jack_set_gating_jack - Set gating jack. 346a11e9b16STakashi Iwai * @codec: the HDA codec 347a11e9b16STakashi Iwai * @gated_nid: gated pin NID 348a11e9b16STakashi Iwai * @gating_nid: gating pin NID 3490619ba8cSDylan Reid * 3500619ba8cSDylan Reid * Indicates the gated jack is only valid when the gating jack is plugged. 3510619ba8cSDylan Reid */ 3520619ba8cSDylan Reid int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, 3530619ba8cSDylan Reid hda_nid_t gating_nid) 3540619ba8cSDylan Reid { 3555204a05dSNikhil Mahale struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0); 3565204a05dSNikhil Mahale struct hda_jack_tbl *gating = 3575204a05dSNikhil Mahale snd_hda_jack_tbl_new(codec, gating_nid, 0); 3585204a05dSNikhil Mahale 3595204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 3600619ba8cSDylan Reid 3610619ba8cSDylan Reid if (!gated || !gating) 3620619ba8cSDylan Reid return -EINVAL; 3630619ba8cSDylan Reid 3640619ba8cSDylan Reid gated->gating_jack = gating_nid; 3650619ba8cSDylan Reid gating->gated_jack = gated_nid; 3660619ba8cSDylan Reid 3670619ba8cSDylan Reid return 0; 3680619ba8cSDylan Reid } 3692698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); 3700619ba8cSDylan Reid 3710619ba8cSDylan Reid /** 37201a61e12STakashi Iwai * snd_hda_jack_report_sync - sync the states of all jacks and report if changed 373a11e9b16STakashi Iwai * @codec: the HDA codec 37401a61e12STakashi Iwai */ 37501a61e12STakashi Iwai void snd_hda_jack_report_sync(struct hda_codec *codec) 37601a61e12STakashi Iwai { 3770619ba8cSDylan Reid struct hda_jack_tbl *jack; 37835be544aSTakashi Iwai int i, state; 37901a61e12STakashi Iwai 3800619ba8cSDylan Reid /* update all jacks at first */ 3810619ba8cSDylan Reid jack = codec->jacktbl.list; 3820619ba8cSDylan Reid for (i = 0; i < codec->jacktbl.used; i++, jack++) 3830619ba8cSDylan Reid if (jack->nid) 3840619ba8cSDylan Reid jack_detect_update(codec, jack); 3850619ba8cSDylan Reid 3860619ba8cSDylan Reid /* report the updated jacks; it's done after updating all jacks 3870619ba8cSDylan Reid * to make sure that all gating jacks properly have been set 3880619ba8cSDylan Reid */ 3890619ba8cSDylan Reid jack = codec->jacktbl.list; 39001a61e12STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 39101a61e12STakashi Iwai if (jack->nid) { 3922ba2dfa1SJie Yang if (!jack->jack || jack->block_report) 393cfc7c9d3STakashi Iwai continue; 394911761c2STakashi Iwai state = jack->button_state; 395911761c2STakashi Iwai if (get_jack_plug_state(jack->pin_sense)) 396911761c2STakashi Iwai state |= jack->type; 397911761c2STakashi Iwai snd_jack_report(jack->jack, state); 398911761c2STakashi Iwai if (jack->button_state) { 39931ef2257STakashi Iwai snd_jack_report(jack->jack, 400911761c2STakashi Iwai state & ~jack->button_state); 401911761c2STakashi Iwai jack->button_state = 0; /* button released */ 402911761c2STakashi Iwai } 40301a61e12STakashi Iwai } 40401a61e12STakashi Iwai } 4052698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); 40601a61e12STakashi Iwai 40731ef2257STakashi Iwai /* guess the jack type from the pin-config */ 40831ef2257STakashi Iwai static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) 40931ef2257STakashi Iwai { 41031ef2257STakashi Iwai unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 41131ef2257STakashi Iwai switch (get_defcfg_device(def_conf)) { 41231ef2257STakashi Iwai case AC_JACK_LINE_OUT: 41331ef2257STakashi Iwai case AC_JACK_SPEAKER: 41431ef2257STakashi Iwai return SND_JACK_LINEOUT; 41531ef2257STakashi Iwai case AC_JACK_HP_OUT: 41631ef2257STakashi Iwai return SND_JACK_HEADPHONE; 41731ef2257STakashi Iwai case AC_JACK_SPDIF_OUT: 41831ef2257STakashi Iwai case AC_JACK_DIG_OTHER_OUT: 41931ef2257STakashi Iwai return SND_JACK_AVOUT; 42031ef2257STakashi Iwai case AC_JACK_MIC_IN: 42131ef2257STakashi Iwai return SND_JACK_MICROPHONE; 42231ef2257STakashi Iwai default: 42331ef2257STakashi Iwai return SND_JACK_LINEIN; 42431ef2257STakashi Iwai } 42531ef2257STakashi Iwai } 42631ef2257STakashi Iwai 42731ef2257STakashi Iwai static void hda_free_jack_priv(struct snd_jack *jack) 42831ef2257STakashi Iwai { 42931ef2257STakashi Iwai struct hda_jack_tbl *jacks = jack->private_data; 43031ef2257STakashi Iwai jacks->nid = 0; 43131ef2257STakashi Iwai jacks->jack = NULL; 43231ef2257STakashi Iwai } 43331ef2257STakashi Iwai 43401a61e12STakashi Iwai /** 4355204a05dSNikhil Mahale * snd_hda_jack_add_kctl_mst - Add a kctl for the given pin 436a11e9b16STakashi Iwai * @codec: the HDA codec 437a11e9b16STakashi Iwai * @nid: pin NID to assign 4385204a05dSNikhil Mahale * @dev_id : pin device entry id 439a11e9b16STakashi Iwai * @name: string name for the jack 440a11e9b16STakashi Iwai * @phantom_jack: flag to deal as a phantom jack 441911761c2STakashi Iwai * @type: jack type bits to be reported, 0 for guessing from pincfg 442911761c2STakashi Iwai * @keymap: optional jack / key mapping 44301a61e12STakashi Iwai * 44401a61e12STakashi Iwai * This assigns a jack-detection kctl to the given pin. The kcontrol 44501a61e12STakashi Iwai * will have the given name and index. 44601a61e12STakashi Iwai */ 4475204a05dSNikhil Mahale int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, 4485204a05dSNikhil Mahale int dev_id, const char *name, bool phantom_jack, 449911761c2STakashi Iwai int type, const struct hda_jack_keymap *keymap) 45001a61e12STakashi Iwai { 45101a61e12STakashi Iwai struct hda_jack_tbl *jack; 452911761c2STakashi Iwai const struct hda_jack_keymap *map; 453911761c2STakashi Iwai int err, state, buttons; 45401a61e12STakashi Iwai 4555204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 45601a61e12STakashi Iwai if (!jack) 45701a61e12STakashi Iwai return 0; 4582ba2dfa1SJie Yang if (jack->jack) 45901a61e12STakashi Iwai return 0; /* already created */ 46080c8bfbeSDavid Henningsson 461911761c2STakashi Iwai if (!type) 4622ba2dfa1SJie Yang type = get_input_jack_type(codec, nid); 463911761c2STakashi Iwai 464911761c2STakashi Iwai buttons = 0; 465911761c2STakashi Iwai if (keymap) { 466911761c2STakashi Iwai for (map = keymap; map->type; map++) 467911761c2STakashi Iwai buttons |= map->type; 468911761c2STakashi Iwai } 469911761c2STakashi Iwai 470911761c2STakashi Iwai err = snd_jack_new(codec->card, name, type | buttons, 4712ba2dfa1SJie Yang &jack->jack, true, phantom_jack); 47231ef2257STakashi Iwai if (err < 0) 47331ef2257STakashi Iwai return err; 4742ba2dfa1SJie Yang 4752ba2dfa1SJie Yang jack->phantom_jack = !!phantom_jack; 4762ba2dfa1SJie Yang jack->type = type; 477911761c2STakashi Iwai jack->button_state = 0; 47831ef2257STakashi Iwai jack->jack->private_data = jack; 47931ef2257STakashi Iwai jack->jack->private_free = hda_free_jack_priv; 480911761c2STakashi Iwai if (keymap) { 481911761c2STakashi Iwai for (map = keymap; map->type; map++) 482911761c2STakashi Iwai snd_jack_set_key(jack->jack, map->type, map->key); 483911761c2STakashi Iwai } 484911761c2STakashi Iwai 4855204a05dSNikhil Mahale state = snd_hda_jack_detect_mst(codec, nid, dev_id); 48631ef2257STakashi Iwai snd_jack_report(jack->jack, state ? jack->type : 0); 4872ba2dfa1SJie Yang 48801a61e12STakashi Iwai return 0; 48901a61e12STakashi Iwai } 4905204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst); 49101a61e12STakashi Iwai 492201e06ffSTakashi Iwai static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, 493b26b5116SDavid Henningsson const struct auto_pin_cfg *cfg, 494b26b5116SDavid Henningsson const char *base_name) 49501a61e12STakashi Iwai { 4963a93897eSTakashi Iwai unsigned int def_conf, conn; 497975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 4982ba2dfa1SJie Yang int err; 49980c8bfbeSDavid Henningsson bool phantom_jack; 5003a93897eSTakashi Iwai 5015204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 5025204a05dSNikhil Mahale 50301a61e12STakashi Iwai if (!nid) 50401a61e12STakashi Iwai return 0; 5053a93897eSTakashi Iwai def_conf = snd_hda_codec_get_pincfg(codec, nid); 5063a93897eSTakashi Iwai conn = get_defcfg_connect(def_conf); 50780c8bfbeSDavid Henningsson if (conn == AC_JACK_PORT_NONE) 5083a93897eSTakashi Iwai return 0; 50980c8bfbeSDavid Henningsson phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || 51080c8bfbeSDavid Henningsson !is_jack_detectable(codec, nid); 5113a93897eSTakashi Iwai 5122ba2dfa1SJie Yang if (base_name) 513b26b5116SDavid Henningsson strlcpy(name, base_name, sizeof(name)); 5142ba2dfa1SJie Yang else 5152ba2dfa1SJie Yang snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); 51680c8bfbeSDavid Henningsson if (phantom_jack) 51780c8bfbeSDavid Henningsson /* Example final name: "Internal Mic Phantom Jack" */ 51880c8bfbeSDavid Henningsson strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); 519911761c2STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); 5203a93897eSTakashi Iwai if (err < 0) 5213a93897eSTakashi Iwai return err; 52280c8bfbeSDavid Henningsson 52380c8bfbeSDavid Henningsson if (!phantom_jack) 5245204a05dSNikhil Mahale return snd_hda_jack_detect_enable(codec, nid, 0); 52580c8bfbeSDavid Henningsson return 0; 52601a61e12STakashi Iwai } 52701a61e12STakashi Iwai 52801a61e12STakashi Iwai /** 52901a61e12STakashi Iwai * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg 530a11e9b16STakashi Iwai * @codec: the HDA codec 531a11e9b16STakashi Iwai * @cfg: pin config table to parse 53201a61e12STakashi Iwai */ 53301a61e12STakashi Iwai int snd_hda_jack_add_kctls(struct hda_codec *codec, 53401a61e12STakashi Iwai const struct auto_pin_cfg *cfg) 53501a61e12STakashi Iwai { 53601a61e12STakashi Iwai const hda_nid_t *p; 537f46c3296STakashi Iwai int i, err; 53801a61e12STakashi Iwai 539b26b5116SDavid Henningsson for (i = 0; i < cfg->num_inputs; i++) { 540b26b5116SDavid Henningsson /* If we have headphone mics; make sure they get the right name 541b26b5116SDavid Henningsson before grabbed by output pins */ 542b26b5116SDavid Henningsson if (cfg->inputs[i].is_headphone_mic) { 543b26b5116SDavid Henningsson if (auto_cfg_hp_outs(cfg) == 1) 544b26b5116SDavid Henningsson err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0], 545b26b5116SDavid Henningsson cfg, "Headphone Mic"); 546b26b5116SDavid Henningsson else 547b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, 548b26b5116SDavid Henningsson cfg, "Headphone Mic"); 549b26b5116SDavid Henningsson } else 550b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, 551b26b5116SDavid Henningsson NULL); 552b26b5116SDavid Henningsson if (err < 0) 553b26b5116SDavid Henningsson return err; 554b26b5116SDavid Henningsson } 555b26b5116SDavid Henningsson 55601a61e12STakashi Iwai for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { 557b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 55801a61e12STakashi Iwai if (err < 0) 55901a61e12STakashi Iwai return err; 56001a61e12STakashi Iwai } 56101a61e12STakashi Iwai for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { 56201a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 56301a61e12STakashi Iwai break; 564b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 56501a61e12STakashi Iwai if (err < 0) 56601a61e12STakashi Iwai return err; 56701a61e12STakashi Iwai } 56801a61e12STakashi Iwai for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { 56901a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 57001a61e12STakashi Iwai break; 571b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 57201a61e12STakashi Iwai if (err < 0) 57301a61e12STakashi Iwai return err; 57401a61e12STakashi Iwai } 57501a61e12STakashi Iwai for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { 576b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 57701a61e12STakashi Iwai if (err < 0) 57801a61e12STakashi Iwai return err; 57901a61e12STakashi Iwai } 580b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL); 58101a61e12STakashi Iwai if (err < 0) 58201a61e12STakashi Iwai return err; 583b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL); 58401a61e12STakashi Iwai if (err < 0) 58501a61e12STakashi Iwai return err; 58601a61e12STakashi Iwai return 0; 58701a61e12STakashi Iwai } 5882698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); 589954df2a9SDavid Henningsson 590e6ce180fSTakashi Iwai static void call_jack_callback(struct hda_codec *codec, unsigned int res, 5910619ba8cSDylan Reid struct hda_jack_tbl *jack) 5920619ba8cSDylan Reid { 5931a4f69d5STakashi Iwai struct hda_jack_callback *cb; 5941a4f69d5STakashi Iwai 595e6ce180fSTakashi Iwai for (cb = jack->callback; cb; cb = cb->next) { 596e6ce180fSTakashi Iwai cb->jack = jack; 597e6ce180fSTakashi Iwai cb->unsol_res = res; 5981a4f69d5STakashi Iwai cb->func(codec, cb); 599e6ce180fSTakashi Iwai } 6000619ba8cSDylan Reid if (jack->gated_jack) { 6010619ba8cSDylan Reid struct hda_jack_tbl *gated = 6025204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 6035204a05dSNikhil Mahale jack->dev_id); 6041a4f69d5STakashi Iwai if (gated) { 605e6ce180fSTakashi Iwai for (cb = gated->callback; cb; cb = cb->next) { 606e6ce180fSTakashi Iwai cb->jack = gated; 607e6ce180fSTakashi Iwai cb->unsol_res = res; 6081a4f69d5STakashi Iwai cb->func(codec, cb); 6091a4f69d5STakashi Iwai } 6100619ba8cSDylan Reid } 6110619ba8cSDylan Reid } 612e6ce180fSTakashi Iwai } 6130619ba8cSDylan Reid 61495a962c3STakashi Iwai /** 61595a962c3STakashi Iwai * snd_hda_jack_unsol_event - Handle an unsolicited event 61695a962c3STakashi Iwai * @codec: the HDA codec 61795a962c3STakashi Iwai * @res: the unsolicited event data 61895a962c3STakashi Iwai */ 619954df2a9SDavid Henningsson void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) 620954df2a9SDavid Henningsson { 621954df2a9SDavid Henningsson struct hda_jack_tbl *event; 622c7e68a69SGuennadi Liakhovetski int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; 623954df2a9SDavid Henningsson 6245204a05dSNikhil Mahale if (codec->dp_mst) { 6255204a05dSNikhil Mahale int dev_entry = 6265204a05dSNikhil Mahale (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; 6275204a05dSNikhil Mahale 6285204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); 6295204a05dSNikhil Mahale } else { 6305204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); 6315204a05dSNikhil Mahale } 632954df2a9SDavid Henningsson if (!event) 633954df2a9SDavid Henningsson return; 634954df2a9SDavid Henningsson event->jack_dirty = 1; 635954df2a9SDavid Henningsson 636e6ce180fSTakashi Iwai call_jack_callback(codec, res, event); 637954df2a9SDavid Henningsson snd_hda_jack_report_sync(codec); 638954df2a9SDavid Henningsson } 6392698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); 640954df2a9SDavid Henningsson 64195a962c3STakashi Iwai /** 64295a962c3STakashi Iwai * snd_hda_jack_poll_all - Poll all jacks 64395a962c3STakashi Iwai * @codec: the HDA codec 64495a962c3STakashi Iwai * 64595a962c3STakashi Iwai * Poll all detectable jacks with dirty flag, update the status, call 64695a962c3STakashi Iwai * callbacks and call snd_hda_jack_report_sync() if any changes are found. 64795a962c3STakashi Iwai */ 64826a6cb6cSDavid Henningsson void snd_hda_jack_poll_all(struct hda_codec *codec) 64926a6cb6cSDavid Henningsson { 65026a6cb6cSDavid Henningsson struct hda_jack_tbl *jack = codec->jacktbl.list; 65126a6cb6cSDavid Henningsson int i, changes = 0; 65226a6cb6cSDavid Henningsson 65326a6cb6cSDavid Henningsson for (i = 0; i < codec->jacktbl.used; i++, jack++) { 65426a6cb6cSDavid Henningsson unsigned int old_sense; 65526a6cb6cSDavid Henningsson if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) 65626a6cb6cSDavid Henningsson continue; 65726a6cb6cSDavid Henningsson old_sense = get_jack_plug_state(jack->pin_sense); 65826a6cb6cSDavid Henningsson jack_detect_update(codec, jack); 65926a6cb6cSDavid Henningsson if (old_sense == get_jack_plug_state(jack->pin_sense)) 66026a6cb6cSDavid Henningsson continue; 66126a6cb6cSDavid Henningsson changes = 1; 662e6ce180fSTakashi Iwai call_jack_callback(codec, 0, jack); 66326a6cb6cSDavid Henningsson } 66426a6cb6cSDavid Henningsson if (changes) 66526a6cb6cSDavid Henningsson snd_hda_jack_report_sync(codec); 66626a6cb6cSDavid Henningsson } 6672698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_poll_all); 66826a6cb6cSDavid Henningsson 669