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 */ 46*5204a05dSNikhil 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, 58*5204a05dSNikhil 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 /** 65*5204a05dSNikhil 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 68*5204a05dSNikhil Mahale * @dev_id: pin device entry id 691835a0f9STakashi Iwai */ 701835a0f9STakashi Iwai struct hda_jack_tbl * 71*5204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid, int dev_id) 72*5204a05dSNikhil Mahale { 73*5204a05dSNikhil Mahale struct hda_jack_tbl *jack = codec->jacktbl.list; 74*5204a05dSNikhil Mahale int i; 75*5204a05dSNikhil Mahale 76*5204a05dSNikhil Mahale if (!nid || !jack) 77*5204a05dSNikhil Mahale return NULL; 78*5204a05dSNikhil Mahale for (i = 0; i < codec->jacktbl.used; i++, jack++) 79*5204a05dSNikhil Mahale if (jack->nid == nid && jack->dev_id == dev_id) 80*5204a05dSNikhil Mahale return jack; 81*5204a05dSNikhil Mahale return NULL; 82*5204a05dSNikhil Mahale } 83*5204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_mst); 84*5204a05dSNikhil Mahale 85*5204a05dSNikhil Mahale /** 86*5204a05dSNikhil Mahale * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag 87*5204a05dSNikhil Mahale * @codec: the HDA codec 88*5204a05dSNikhil Mahale * @tag: tag value to refer to 89*5204a05dSNikhil Mahale * @dev_id: pin device entry id 90*5204a05dSNikhil Mahale */ 91*5204a05dSNikhil Mahale struct hda_jack_tbl * 92*5204a05dSNikhil Mahale snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, 93*5204a05dSNikhil Mahale unsigned char tag, int dev_id) 94*5204a05dSNikhil Mahale { 95*5204a05dSNikhil Mahale struct hda_jack_tbl *jack = codec->jacktbl.list; 96*5204a05dSNikhil Mahale int i; 97*5204a05dSNikhil Mahale 98*5204a05dSNikhil Mahale if (!tag || !jack) 99*5204a05dSNikhil Mahale return NULL; 100*5204a05dSNikhil Mahale for (i = 0; i < codec->jacktbl.used; i++, jack++) 101*5204a05dSNikhil Mahale if (jack->tag == tag && jack->dev_id == dev_id) 102*5204a05dSNikhil Mahale return jack; 103*5204a05dSNikhil Mahale return NULL; 104*5204a05dSNikhil Mahale } 105*5204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); 106*5204a05dSNikhil Mahale 107*5204a05dSNikhil Mahale static struct hda_jack_tbl * 108*5204a05dSNikhil 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 1251835a0f9STakashi Iwai */ 12681965f1fSTakashi Iwai static struct hda_jack_tbl * 127*5204a05dSNikhil Mahale snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid, int dev_id) 1281835a0f9STakashi Iwai { 129*5204a05dSNikhil Mahale struct hda_jack_tbl *jack = 130*5204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 131*5204a05dSNikhil Mahale struct hda_jack_tbl *existing_nid_jack = 132*5204a05dSNikhil Mahale any_jack_tbl_get_from_nid(codec, nid); 133*5204a05dSNikhil Mahale 134*5204a05dSNikhil Mahale WARN_ON(dev_id != 0 && !codec->dp_mst); 135*5204a05dSNikhil Mahale 1361835a0f9STakashi Iwai if (jack) 1371835a0f9STakashi Iwai return jack; 1381835a0f9STakashi Iwai jack = snd_array_new(&codec->jacktbl); 1391835a0f9STakashi Iwai if (!jack) 1401835a0f9STakashi Iwai return NULL; 1411835a0f9STakashi Iwai jack->nid = nid; 142*5204a05dSNikhil Mahale jack->dev_id = dev_id; 1431835a0f9STakashi Iwai jack->jack_dirty = 1; 144*5204a05dSNikhil Mahale if (existing_nid_jack) { 145*5204a05dSNikhil Mahale jack->tag = existing_nid_jack->tag; 146*5204a05dSNikhil Mahale 147*5204a05dSNikhil Mahale /* 148*5204a05dSNikhil Mahale * Copy jack_detect from existing_nid_jack to avoid 149*5204a05dSNikhil Mahale * snd_hda_jack_detect_enable_callback_mst() making multiple 150*5204a05dSNikhil Mahale * SET_UNSOLICITED_ENABLE calls on the same pin. 151*5204a05dSNikhil Mahale */ 152*5204a05dSNikhil Mahale jack->jack_detect = existing_nid_jack->jack_detect; 153*5204a05dSNikhil Mahale } else { 1543a93897eSTakashi Iwai jack->tag = codec->jacktbl.used; 155*5204a05dSNikhil Mahale } 156*5204a05dSNikhil Mahale 1571835a0f9STakashi Iwai return jack; 1581835a0f9STakashi Iwai } 1591835a0f9STakashi Iwai 1601835a0f9STakashi Iwai void snd_hda_jack_tbl_clear(struct hda_codec *codec) 1611835a0f9STakashi Iwai { 16231ef2257STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 16331ef2257STakashi Iwai int i; 1641a4f69d5STakashi Iwai 16531ef2257STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) { 1661a4f69d5STakashi Iwai struct hda_jack_callback *cb, *next; 1672ba2dfa1SJie Yang 1681a4f69d5STakashi Iwai /* free jack instances manually when clearing/reconfiguring */ 1691a4f69d5STakashi Iwai if (!codec->bus->shutdown && jack->jack) 1706efdd851STakashi Iwai snd_device_free(codec->card, jack->jack); 1712ba2dfa1SJie Yang 1721a4f69d5STakashi Iwai for (cb = jack->callback; cb; cb = next) { 1731a4f69d5STakashi Iwai next = cb->next; 1741a4f69d5STakashi Iwai kfree(cb); 1751a4f69d5STakashi Iwai } 1761a4f69d5STakashi Iwai } 1771835a0f9STakashi Iwai snd_array_free(&codec->jacktbl); 1781835a0f9STakashi Iwai } 1791835a0f9STakashi Iwai 1800619ba8cSDylan Reid #define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) 1810619ba8cSDylan Reid 1821835a0f9STakashi Iwai /* update the cached value and notification flag if needed */ 1831835a0f9STakashi Iwai static void jack_detect_update(struct hda_codec *codec, 1841835a0f9STakashi Iwai struct hda_jack_tbl *jack) 1851835a0f9STakashi Iwai { 18680c8bfbeSDavid Henningsson if (!jack->jack_dirty) 18780c8bfbeSDavid Henningsson return; 18880c8bfbeSDavid Henningsson 18980c8bfbeSDavid Henningsson if (jack->phantom_jack) 19080c8bfbeSDavid Henningsson jack->pin_sense = AC_PINSENSE_PRESENCE; 19180c8bfbeSDavid Henningsson else 192*5204a05dSNikhil Mahale jack->pin_sense = read_pin_sense(codec, jack->nid, 193*5204a05dSNikhil Mahale jack->dev_id); 19480c8bfbeSDavid Henningsson 1950619ba8cSDylan Reid /* A gating jack indicates the jack is invalid if gating is unplugged */ 196*5204a05dSNikhil Mahale if (jack->gating_jack && 197*5204a05dSNikhil Mahale !snd_hda_jack_detect_mst(codec, jack->gating_jack, jack->dev_id)) 1980619ba8cSDylan Reid jack->pin_sense &= ~AC_PINSENSE_PRESENCE; 1990619ba8cSDylan Reid 2001835a0f9STakashi Iwai jack->jack_dirty = 0; 2010619ba8cSDylan Reid 2020619ba8cSDylan Reid /* If a jack is gated by this one update it. */ 2030619ba8cSDylan Reid if (jack->gated_jack) { 2040619ba8cSDylan Reid struct hda_jack_tbl *gated = 205*5204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 206*5204a05dSNikhil Mahale jack->dev_id); 2070619ba8cSDylan Reid if (gated) { 2080619ba8cSDylan Reid gated->jack_dirty = 1; 2090619ba8cSDylan Reid jack_detect_update(codec, gated); 2100619ba8cSDylan Reid } 2110619ba8cSDylan Reid } 2121835a0f9STakashi Iwai } 2131835a0f9STakashi Iwai 2141835a0f9STakashi Iwai /** 2151835a0f9STakashi Iwai * snd_hda_set_dirty_all - Mark all the cached as dirty 216a11e9b16STakashi Iwai * @codec: the HDA codec 2171835a0f9STakashi Iwai * 2181835a0f9STakashi Iwai * This function sets the dirty flag to all entries of jack table. 2191835a0f9STakashi Iwai * It's called from the resume path in hda_codec.c. 2201835a0f9STakashi Iwai */ 2211835a0f9STakashi Iwai void snd_hda_jack_set_dirty_all(struct hda_codec *codec) 2221835a0f9STakashi Iwai { 2231835a0f9STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 2241835a0f9STakashi Iwai int i; 2251835a0f9STakashi Iwai 2261835a0f9STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 2271835a0f9STakashi Iwai if (jack->nid) 2281835a0f9STakashi Iwai jack->jack_dirty = 1; 2291835a0f9STakashi Iwai } 2302698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); 2311835a0f9STakashi Iwai 2321835a0f9STakashi Iwai /** 23380b917a8SNikhil Mahale * snd_hda_jack_pin_sense - execute pin sense measurement 2341835a0f9STakashi Iwai * @codec: the CODEC to sense 2351835a0f9STakashi Iwai * @nid: the pin NID to sense 2361835a0f9STakashi Iwai * 2371835a0f9STakashi Iwai * Execute necessary pin sense measurement and return its Presence Detect, 2381835a0f9STakashi Iwai * Impedance, ELD Valid etc. status bits. 2391835a0f9STakashi Iwai */ 240*5204a05dSNikhil Mahale u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid, int dev_id) 2411835a0f9STakashi Iwai { 242*5204a05dSNikhil Mahale struct hda_jack_tbl *jack = 243*5204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 2441835a0f9STakashi Iwai if (jack) { 2451835a0f9STakashi Iwai jack_detect_update(codec, jack); 2461835a0f9STakashi Iwai return jack->pin_sense; 2471835a0f9STakashi Iwai } 248*5204a05dSNikhil Mahale return read_pin_sense(codec, nid, dev_id); 2491835a0f9STakashi Iwai } 25080b917a8SNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); 2511835a0f9STakashi Iwai 2521835a0f9STakashi Iwai /** 253*5204a05dSNikhil Mahale * snd_hda_jack_detect_state_mst - query pin Presence Detect status 2541835a0f9STakashi Iwai * @codec: the CODEC to sense 2551835a0f9STakashi Iwai * @nid: the pin NID to sense 256*5204a05dSNikhil Mahale * @dev_id: pin device entry id 2571835a0f9STakashi Iwai * 25860ea8ca2STakashi Iwai * Query and return the pin's Presence Detect status, as either 25960ea8ca2STakashi Iwai * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. 2601835a0f9STakashi Iwai */ 261*5204a05dSNikhil Mahale int snd_hda_jack_detect_state_mst(struct hda_codec *codec, 262*5204a05dSNikhil Mahale hda_nid_t nid, int dev_id) 2631835a0f9STakashi Iwai { 264*5204a05dSNikhil Mahale struct hda_jack_tbl *jack = 265*5204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, nid, dev_id); 26660ea8ca2STakashi Iwai if (jack && jack->phantom_jack) 26760ea8ca2STakashi Iwai return HDA_JACK_PHANTOM; 268*5204a05dSNikhil Mahale else if (snd_hda_jack_pin_sense(codec, nid, dev_id) & 269*5204a05dSNikhil Mahale AC_PINSENSE_PRESENCE) 27060ea8ca2STakashi Iwai return HDA_JACK_PRESENT; 27160ea8ca2STakashi Iwai else 27260ea8ca2STakashi Iwai return HDA_JACK_NOT_PRESENT; 2731835a0f9STakashi Iwai } 274*5204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst); 2751835a0f9STakashi Iwai 2761835a0f9STakashi Iwai /** 277*5204a05dSNikhil Mahale * snd_hda_jack_detect_enable_mst - enable the jack-detection 278a11e9b16STakashi Iwai * @codec: the HDA codec 279a11e9b16STakashi Iwai * @nid: pin NID to enable 280a11e9b16STakashi Iwai * @func: callback function to register 281*5204a05dSNikhil Mahale * @dev_id: pin device entry id 282bda17b82STakashi Iwai * 283bda17b82STakashi Iwai * In the case of error, the return value will be a pointer embedded with 284bda17b82STakashi Iwai * errno. Check and handle the return value appropriately with standard 285bda17b82STakashi Iwai * macros such as @IS_ERR() and @PTR_ERR(). 2861835a0f9STakashi Iwai */ 2871a4f69d5STakashi Iwai struct hda_jack_callback * 288*5204a05dSNikhil Mahale snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid, 289*5204a05dSNikhil Mahale int dev_id, hda_jack_callback_fn func) 2901835a0f9STakashi Iwai { 2911a4f69d5STakashi Iwai struct hda_jack_tbl *jack; 2921a4f69d5STakashi Iwai struct hda_jack_callback *callback = NULL; 293bda17b82STakashi Iwai int err; 294bda17b82STakashi Iwai 295*5204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 2961835a0f9STakashi Iwai if (!jack) 297bda17b82STakashi Iwai return ERR_PTR(-ENOMEM); 2981a4f69d5STakashi Iwai if (func) { 2991a4f69d5STakashi Iwai callback = kzalloc(sizeof(*callback), GFP_KERNEL); 3001a4f69d5STakashi Iwai if (!callback) 3011a4f69d5STakashi Iwai return ERR_PTR(-ENOMEM); 3021a4f69d5STakashi Iwai callback->func = func; 3032ebab40eSTakashi Iwai callback->nid = jack->nid; 304*5204a05dSNikhil Mahale callback->dev_id = jack->dev_id; 3051a4f69d5STakashi Iwai callback->next = jack->callback; 3061a4f69d5STakashi Iwai jack->callback = callback; 3071a4f69d5STakashi Iwai } 3081a4f69d5STakashi Iwai 3093a93897eSTakashi Iwai if (jack->jack_detect) 3101a4f69d5STakashi Iwai return callback; /* already registered */ 3113a93897eSTakashi Iwai jack->jack_detect = 1; 31234a93187SDavid Henningsson if (codec->jackpoll_interval > 0) 3131a4f69d5STakashi Iwai return callback; /* No unsol if we're polling instead */ 314bda17b82STakashi Iwai err = snd_hda_codec_write_cache(codec, nid, 0, 3151835a0f9STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 3163a93897eSTakashi Iwai AC_USRSP_EN | jack->tag); 317bda17b82STakashi Iwai if (err < 0) 318bda17b82STakashi Iwai return ERR_PTR(err); 3191a4f69d5STakashi Iwai return callback; 3201835a0f9STakashi Iwai } 321*5204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst); 322954df2a9SDavid Henningsson 32395a962c3STakashi Iwai /** 32495a962c3STakashi Iwai * snd_hda_jack_detect_enable - Enable the jack detection on the given pin 32595a962c3STakashi Iwai * @codec: the HDA codec 32695a962c3STakashi Iwai * @nid: pin NID to enable jack detection 327*5204a05dSNikhil Mahale * @dev_id: pin device entry id 32895a962c3STakashi Iwai * 32995a962c3STakashi Iwai * Enable the jack detection with the default callback. Returns zero if 33095a962c3STakashi Iwai * successful or a negative error code. 33195a962c3STakashi Iwai */ 332*5204a05dSNikhil Mahale int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, 333*5204a05dSNikhil Mahale int dev_id) 334954df2a9SDavid Henningsson { 335*5204a05dSNikhil Mahale return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback_mst(codec, 336*5204a05dSNikhil Mahale nid, 337*5204a05dSNikhil Mahale dev_id, 338*5204a05dSNikhil Mahale NULL)); 339954df2a9SDavid Henningsson } 3402698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); 34101a61e12STakashi Iwai 34201a61e12STakashi Iwai /** 3430619ba8cSDylan Reid * snd_hda_jack_set_gating_jack - Set gating jack. 344a11e9b16STakashi Iwai * @codec: the HDA codec 345a11e9b16STakashi Iwai * @gated_nid: gated pin NID 346a11e9b16STakashi Iwai * @gating_nid: gating pin NID 3470619ba8cSDylan Reid * 3480619ba8cSDylan Reid * Indicates the gated jack is only valid when the gating jack is plugged. 3490619ba8cSDylan Reid */ 3500619ba8cSDylan Reid int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, 3510619ba8cSDylan Reid hda_nid_t gating_nid) 3520619ba8cSDylan Reid { 353*5204a05dSNikhil Mahale struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0); 354*5204a05dSNikhil Mahale struct hda_jack_tbl *gating = 355*5204a05dSNikhil Mahale snd_hda_jack_tbl_new(codec, gating_nid, 0); 356*5204a05dSNikhil Mahale 357*5204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 3580619ba8cSDylan Reid 3590619ba8cSDylan Reid if (!gated || !gating) 3600619ba8cSDylan Reid return -EINVAL; 3610619ba8cSDylan Reid 3620619ba8cSDylan Reid gated->gating_jack = gating_nid; 3630619ba8cSDylan Reid gating->gated_jack = gated_nid; 3640619ba8cSDylan Reid 3650619ba8cSDylan Reid return 0; 3660619ba8cSDylan Reid } 3672698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); 3680619ba8cSDylan Reid 3690619ba8cSDylan Reid /** 37001a61e12STakashi Iwai * snd_hda_jack_report_sync - sync the states of all jacks and report if changed 371a11e9b16STakashi Iwai * @codec: the HDA codec 37201a61e12STakashi Iwai */ 37301a61e12STakashi Iwai void snd_hda_jack_report_sync(struct hda_codec *codec) 37401a61e12STakashi Iwai { 3750619ba8cSDylan Reid struct hda_jack_tbl *jack; 37635be544aSTakashi Iwai int i, state; 37701a61e12STakashi Iwai 3780619ba8cSDylan Reid /* update all jacks at first */ 3790619ba8cSDylan Reid jack = codec->jacktbl.list; 3800619ba8cSDylan Reid for (i = 0; i < codec->jacktbl.used; i++, jack++) 3810619ba8cSDylan Reid if (jack->nid) 3820619ba8cSDylan Reid jack_detect_update(codec, jack); 3830619ba8cSDylan Reid 3840619ba8cSDylan Reid /* report the updated jacks; it's done after updating all jacks 3850619ba8cSDylan Reid * to make sure that all gating jacks properly have been set 3860619ba8cSDylan Reid */ 3870619ba8cSDylan Reid jack = codec->jacktbl.list; 38801a61e12STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 38901a61e12STakashi Iwai if (jack->nid) { 3902ba2dfa1SJie Yang if (!jack->jack || jack->block_report) 391cfc7c9d3STakashi Iwai continue; 392911761c2STakashi Iwai state = jack->button_state; 393911761c2STakashi Iwai if (get_jack_plug_state(jack->pin_sense)) 394911761c2STakashi Iwai state |= jack->type; 395911761c2STakashi Iwai snd_jack_report(jack->jack, state); 396911761c2STakashi Iwai if (jack->button_state) { 39731ef2257STakashi Iwai snd_jack_report(jack->jack, 398911761c2STakashi Iwai state & ~jack->button_state); 399911761c2STakashi Iwai jack->button_state = 0; /* button released */ 400911761c2STakashi Iwai } 40101a61e12STakashi Iwai } 40201a61e12STakashi Iwai } 4032698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); 40401a61e12STakashi Iwai 40531ef2257STakashi Iwai /* guess the jack type from the pin-config */ 40631ef2257STakashi Iwai static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) 40731ef2257STakashi Iwai { 40831ef2257STakashi Iwai unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 40931ef2257STakashi Iwai switch (get_defcfg_device(def_conf)) { 41031ef2257STakashi Iwai case AC_JACK_LINE_OUT: 41131ef2257STakashi Iwai case AC_JACK_SPEAKER: 41231ef2257STakashi Iwai return SND_JACK_LINEOUT; 41331ef2257STakashi Iwai case AC_JACK_HP_OUT: 41431ef2257STakashi Iwai return SND_JACK_HEADPHONE; 41531ef2257STakashi Iwai case AC_JACK_SPDIF_OUT: 41631ef2257STakashi Iwai case AC_JACK_DIG_OTHER_OUT: 41731ef2257STakashi Iwai return SND_JACK_AVOUT; 41831ef2257STakashi Iwai case AC_JACK_MIC_IN: 41931ef2257STakashi Iwai return SND_JACK_MICROPHONE; 42031ef2257STakashi Iwai default: 42131ef2257STakashi Iwai return SND_JACK_LINEIN; 42231ef2257STakashi Iwai } 42331ef2257STakashi Iwai } 42431ef2257STakashi Iwai 42531ef2257STakashi Iwai static void hda_free_jack_priv(struct snd_jack *jack) 42631ef2257STakashi Iwai { 42731ef2257STakashi Iwai struct hda_jack_tbl *jacks = jack->private_data; 42831ef2257STakashi Iwai jacks->nid = 0; 42931ef2257STakashi Iwai jacks->jack = NULL; 43031ef2257STakashi Iwai } 43131ef2257STakashi Iwai 43201a61e12STakashi Iwai /** 433*5204a05dSNikhil Mahale * snd_hda_jack_add_kctl_mst - Add a kctl for the given pin 434a11e9b16STakashi Iwai * @codec: the HDA codec 435a11e9b16STakashi Iwai * @nid: pin NID to assign 436*5204a05dSNikhil Mahale * @dev_id : pin device entry id 437a11e9b16STakashi Iwai * @name: string name for the jack 438a11e9b16STakashi Iwai * @phantom_jack: flag to deal as a phantom jack 439911761c2STakashi Iwai * @type: jack type bits to be reported, 0 for guessing from pincfg 440911761c2STakashi Iwai * @keymap: optional jack / key mapping 44101a61e12STakashi Iwai * 44201a61e12STakashi Iwai * This assigns a jack-detection kctl to the given pin. The kcontrol 44301a61e12STakashi Iwai * will have the given name and index. 44401a61e12STakashi Iwai */ 445*5204a05dSNikhil Mahale int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid, 446*5204a05dSNikhil Mahale int dev_id, const char *name, bool phantom_jack, 447911761c2STakashi Iwai int type, const struct hda_jack_keymap *keymap) 44801a61e12STakashi Iwai { 44901a61e12STakashi Iwai struct hda_jack_tbl *jack; 450911761c2STakashi Iwai const struct hda_jack_keymap *map; 451911761c2STakashi Iwai int err, state, buttons; 45201a61e12STakashi Iwai 453*5204a05dSNikhil Mahale jack = snd_hda_jack_tbl_new(codec, nid, dev_id); 45401a61e12STakashi Iwai if (!jack) 45501a61e12STakashi Iwai return 0; 4562ba2dfa1SJie Yang if (jack->jack) 45701a61e12STakashi Iwai return 0; /* already created */ 45880c8bfbeSDavid Henningsson 459911761c2STakashi Iwai if (!type) 4602ba2dfa1SJie Yang type = get_input_jack_type(codec, nid); 461911761c2STakashi Iwai 462911761c2STakashi Iwai buttons = 0; 463911761c2STakashi Iwai if (keymap) { 464911761c2STakashi Iwai for (map = keymap; map->type; map++) 465911761c2STakashi Iwai buttons |= map->type; 466911761c2STakashi Iwai } 467911761c2STakashi Iwai 468911761c2STakashi Iwai err = snd_jack_new(codec->card, name, type | buttons, 4692ba2dfa1SJie Yang &jack->jack, true, phantom_jack); 47031ef2257STakashi Iwai if (err < 0) 47131ef2257STakashi Iwai return err; 4722ba2dfa1SJie Yang 4732ba2dfa1SJie Yang jack->phantom_jack = !!phantom_jack; 4742ba2dfa1SJie Yang jack->type = type; 475911761c2STakashi Iwai jack->button_state = 0; 47631ef2257STakashi Iwai jack->jack->private_data = jack; 47731ef2257STakashi Iwai jack->jack->private_free = hda_free_jack_priv; 478911761c2STakashi Iwai if (keymap) { 479911761c2STakashi Iwai for (map = keymap; map->type; map++) 480911761c2STakashi Iwai snd_jack_set_key(jack->jack, map->type, map->key); 481911761c2STakashi Iwai } 482911761c2STakashi Iwai 483*5204a05dSNikhil Mahale state = snd_hda_jack_detect_mst(codec, nid, dev_id); 48431ef2257STakashi Iwai snd_jack_report(jack->jack, state ? jack->type : 0); 4852ba2dfa1SJie Yang 48601a61e12STakashi Iwai return 0; 48701a61e12STakashi Iwai } 488*5204a05dSNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst); 48901a61e12STakashi Iwai 490201e06ffSTakashi Iwai static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, 491b26b5116SDavid Henningsson const struct auto_pin_cfg *cfg, 492b26b5116SDavid Henningsson const char *base_name) 49301a61e12STakashi Iwai { 4943a93897eSTakashi Iwai unsigned int def_conf, conn; 495975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 4962ba2dfa1SJie Yang int err; 49780c8bfbeSDavid Henningsson bool phantom_jack; 4983a93897eSTakashi Iwai 499*5204a05dSNikhil Mahale WARN_ON(codec->dp_mst); 500*5204a05dSNikhil Mahale 50101a61e12STakashi Iwai if (!nid) 50201a61e12STakashi Iwai return 0; 5033a93897eSTakashi Iwai def_conf = snd_hda_codec_get_pincfg(codec, nid); 5043a93897eSTakashi Iwai conn = get_defcfg_connect(def_conf); 50580c8bfbeSDavid Henningsson if (conn == AC_JACK_PORT_NONE) 5063a93897eSTakashi Iwai return 0; 50780c8bfbeSDavid Henningsson phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || 50880c8bfbeSDavid Henningsson !is_jack_detectable(codec, nid); 5093a93897eSTakashi Iwai 5102ba2dfa1SJie Yang if (base_name) 511b26b5116SDavid Henningsson strlcpy(name, base_name, sizeof(name)); 5122ba2dfa1SJie Yang else 5132ba2dfa1SJie Yang snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); 51480c8bfbeSDavid Henningsson if (phantom_jack) 51580c8bfbeSDavid Henningsson /* Example final name: "Internal Mic Phantom Jack" */ 51680c8bfbeSDavid Henningsson strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); 517911761c2STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); 5183a93897eSTakashi Iwai if (err < 0) 5193a93897eSTakashi Iwai return err; 52080c8bfbeSDavid Henningsson 52180c8bfbeSDavid Henningsson if (!phantom_jack) 522*5204a05dSNikhil Mahale return snd_hda_jack_detect_enable(codec, nid, 0); 52380c8bfbeSDavid Henningsson return 0; 52401a61e12STakashi Iwai } 52501a61e12STakashi Iwai 52601a61e12STakashi Iwai /** 52701a61e12STakashi Iwai * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg 528a11e9b16STakashi Iwai * @codec: the HDA codec 529a11e9b16STakashi Iwai * @cfg: pin config table to parse 53001a61e12STakashi Iwai */ 53101a61e12STakashi Iwai int snd_hda_jack_add_kctls(struct hda_codec *codec, 53201a61e12STakashi Iwai const struct auto_pin_cfg *cfg) 53301a61e12STakashi Iwai { 53401a61e12STakashi Iwai const hda_nid_t *p; 535f46c3296STakashi Iwai int i, err; 53601a61e12STakashi Iwai 537b26b5116SDavid Henningsson for (i = 0; i < cfg->num_inputs; i++) { 538b26b5116SDavid Henningsson /* If we have headphone mics; make sure they get the right name 539b26b5116SDavid Henningsson before grabbed by output pins */ 540b26b5116SDavid Henningsson if (cfg->inputs[i].is_headphone_mic) { 541b26b5116SDavid Henningsson if (auto_cfg_hp_outs(cfg) == 1) 542b26b5116SDavid Henningsson err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0], 543b26b5116SDavid Henningsson cfg, "Headphone Mic"); 544b26b5116SDavid Henningsson else 545b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, 546b26b5116SDavid Henningsson cfg, "Headphone Mic"); 547b26b5116SDavid Henningsson } else 548b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, 549b26b5116SDavid Henningsson NULL); 550b26b5116SDavid Henningsson if (err < 0) 551b26b5116SDavid Henningsson return err; 552b26b5116SDavid Henningsson } 553b26b5116SDavid Henningsson 55401a61e12STakashi Iwai for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { 555b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 55601a61e12STakashi Iwai if (err < 0) 55701a61e12STakashi Iwai return err; 55801a61e12STakashi Iwai } 55901a61e12STakashi Iwai for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { 56001a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 56101a61e12STakashi Iwai break; 562b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 56301a61e12STakashi Iwai if (err < 0) 56401a61e12STakashi Iwai return err; 56501a61e12STakashi Iwai } 56601a61e12STakashi Iwai for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { 56701a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 56801a61e12STakashi Iwai break; 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->dig_out_pins; i < cfg->dig_outs; i++, p++) { 574b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 57501a61e12STakashi Iwai if (err < 0) 57601a61e12STakashi Iwai return err; 57701a61e12STakashi Iwai } 578b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL); 57901a61e12STakashi Iwai if (err < 0) 58001a61e12STakashi Iwai return err; 581b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL); 58201a61e12STakashi Iwai if (err < 0) 58301a61e12STakashi Iwai return err; 58401a61e12STakashi Iwai return 0; 58501a61e12STakashi Iwai } 5862698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); 587954df2a9SDavid Henningsson 588e6ce180fSTakashi Iwai static void call_jack_callback(struct hda_codec *codec, unsigned int res, 5890619ba8cSDylan Reid struct hda_jack_tbl *jack) 5900619ba8cSDylan Reid { 5911a4f69d5STakashi Iwai struct hda_jack_callback *cb; 5921a4f69d5STakashi Iwai 593e6ce180fSTakashi Iwai for (cb = jack->callback; cb; cb = cb->next) { 594e6ce180fSTakashi Iwai cb->jack = jack; 595e6ce180fSTakashi Iwai cb->unsol_res = res; 5961a4f69d5STakashi Iwai cb->func(codec, cb); 597e6ce180fSTakashi Iwai } 5980619ba8cSDylan Reid if (jack->gated_jack) { 5990619ba8cSDylan Reid struct hda_jack_tbl *gated = 600*5204a05dSNikhil Mahale snd_hda_jack_tbl_get_mst(codec, jack->gated_jack, 601*5204a05dSNikhil Mahale jack->dev_id); 6021a4f69d5STakashi Iwai if (gated) { 603e6ce180fSTakashi Iwai for (cb = gated->callback; cb; cb = cb->next) { 604e6ce180fSTakashi Iwai cb->jack = gated; 605e6ce180fSTakashi Iwai cb->unsol_res = res; 6061a4f69d5STakashi Iwai cb->func(codec, cb); 6071a4f69d5STakashi Iwai } 6080619ba8cSDylan Reid } 6090619ba8cSDylan Reid } 610e6ce180fSTakashi Iwai } 6110619ba8cSDylan Reid 61295a962c3STakashi Iwai /** 61395a962c3STakashi Iwai * snd_hda_jack_unsol_event - Handle an unsolicited event 61495a962c3STakashi Iwai * @codec: the HDA codec 61595a962c3STakashi Iwai * @res: the unsolicited event data 61695a962c3STakashi Iwai */ 617954df2a9SDavid Henningsson void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) 618954df2a9SDavid Henningsson { 619954df2a9SDavid Henningsson struct hda_jack_tbl *event; 620c7e68a69SGuennadi Liakhovetski int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; 621954df2a9SDavid Henningsson 622*5204a05dSNikhil Mahale if (codec->dp_mst) { 623*5204a05dSNikhil Mahale int dev_entry = 624*5204a05dSNikhil Mahale (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; 625*5204a05dSNikhil Mahale 626*5204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry); 627*5204a05dSNikhil Mahale } else { 628*5204a05dSNikhil Mahale event = snd_hda_jack_tbl_get_from_tag(codec, tag, 0); 629*5204a05dSNikhil Mahale } 630954df2a9SDavid Henningsson if (!event) 631954df2a9SDavid Henningsson return; 632954df2a9SDavid Henningsson event->jack_dirty = 1; 633954df2a9SDavid Henningsson 634e6ce180fSTakashi Iwai call_jack_callback(codec, res, event); 635954df2a9SDavid Henningsson snd_hda_jack_report_sync(codec); 636954df2a9SDavid Henningsson } 6372698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); 638954df2a9SDavid Henningsson 63995a962c3STakashi Iwai /** 64095a962c3STakashi Iwai * snd_hda_jack_poll_all - Poll all jacks 64195a962c3STakashi Iwai * @codec: the HDA codec 64295a962c3STakashi Iwai * 64395a962c3STakashi Iwai * Poll all detectable jacks with dirty flag, update the status, call 64495a962c3STakashi Iwai * callbacks and call snd_hda_jack_report_sync() if any changes are found. 64595a962c3STakashi Iwai */ 64626a6cb6cSDavid Henningsson void snd_hda_jack_poll_all(struct hda_codec *codec) 64726a6cb6cSDavid Henningsson { 64826a6cb6cSDavid Henningsson struct hda_jack_tbl *jack = codec->jacktbl.list; 64926a6cb6cSDavid Henningsson int i, changes = 0; 65026a6cb6cSDavid Henningsson 65126a6cb6cSDavid Henningsson for (i = 0; i < codec->jacktbl.used; i++, jack++) { 65226a6cb6cSDavid Henningsson unsigned int old_sense; 65326a6cb6cSDavid Henningsson if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) 65426a6cb6cSDavid Henningsson continue; 65526a6cb6cSDavid Henningsson old_sense = get_jack_plug_state(jack->pin_sense); 65626a6cb6cSDavid Henningsson jack_detect_update(codec, jack); 65726a6cb6cSDavid Henningsson if (old_sense == get_jack_plug_state(jack->pin_sense)) 65826a6cb6cSDavid Henningsson continue; 65926a6cb6cSDavid Henningsson changes = 1; 660e6ce180fSTakashi Iwai call_jack_callback(codec, 0, jack); 66126a6cb6cSDavid Henningsson } 66226a6cb6cSDavid Henningsson if (changes) 66326a6cb6cSDavid Henningsson snd_hda_jack_report_sync(codec); 66426a6cb6cSDavid Henningsson } 6652698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_poll_all); 66626a6cb6cSDavid Henningsson 667