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 */ 461835a0f9STakashi Iwai static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) 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, 581835a0f9STakashi Iwai AC_VERB_GET_PIN_SENSE, 0); 599cc159c6STakashi Iwai if (codec->inv_jack_detect) 609cc159c6STakashi Iwai val ^= AC_PINSENSE_PRESENCE; 619cc159c6STakashi Iwai return val; 621835a0f9STakashi Iwai } 631835a0f9STakashi Iwai 641835a0f9STakashi Iwai /** 651835a0f9STakashi Iwai * snd_hda_jack_tbl_get - query the jack-table entry for the given NID 66a11e9b16STakashi Iwai * @codec: the HDA codec 67a11e9b16STakashi Iwai * @nid: pin NID to refer to 681835a0f9STakashi Iwai */ 691835a0f9STakashi Iwai struct hda_jack_tbl * 701835a0f9STakashi Iwai snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) 711835a0f9STakashi Iwai { 721835a0f9STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 731835a0f9STakashi Iwai int i; 741835a0f9STakashi Iwai 751835a0f9STakashi Iwai if (!nid || !jack) 761835a0f9STakashi Iwai return NULL; 771835a0f9STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 781835a0f9STakashi Iwai if (jack->nid == nid) 791835a0f9STakashi Iwai return jack; 801835a0f9STakashi Iwai return NULL; 811835a0f9STakashi Iwai } 822698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get); 831835a0f9STakashi Iwai 841835a0f9STakashi Iwai /** 853a93897eSTakashi Iwai * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag 86a11e9b16STakashi Iwai * @codec: the HDA codec 87a11e9b16STakashi Iwai * @tag: tag value to refer to 883a93897eSTakashi Iwai */ 893a93897eSTakashi Iwai struct hda_jack_tbl * 903a93897eSTakashi Iwai snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag) 913a93897eSTakashi Iwai { 923a93897eSTakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 933a93897eSTakashi Iwai int i; 943a93897eSTakashi Iwai 953a93897eSTakashi Iwai if (!tag || !jack) 963a93897eSTakashi Iwai return NULL; 973a93897eSTakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 983a93897eSTakashi Iwai if (jack->tag == tag) 993a93897eSTakashi Iwai return jack; 1003a93897eSTakashi Iwai return NULL; 1013a93897eSTakashi Iwai } 1022698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); 1033a93897eSTakashi Iwai 1043a93897eSTakashi Iwai /** 1051835a0f9STakashi Iwai * snd_hda_jack_tbl_new - create a jack-table entry for the given NID 106a11e9b16STakashi Iwai * @codec: the HDA codec 107a11e9b16STakashi Iwai * @nid: pin NID to assign 1081835a0f9STakashi Iwai */ 10981965f1fSTakashi Iwai static struct hda_jack_tbl * 1101835a0f9STakashi Iwai snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) 1111835a0f9STakashi Iwai { 1121835a0f9STakashi Iwai struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); 1131835a0f9STakashi Iwai if (jack) 1141835a0f9STakashi Iwai return jack; 1151835a0f9STakashi Iwai jack = snd_array_new(&codec->jacktbl); 1161835a0f9STakashi Iwai if (!jack) 1171835a0f9STakashi Iwai return NULL; 1181835a0f9STakashi Iwai jack->nid = nid; 1191835a0f9STakashi Iwai jack->jack_dirty = 1; 1203a93897eSTakashi Iwai jack->tag = codec->jacktbl.used; 1211835a0f9STakashi Iwai return jack; 1221835a0f9STakashi Iwai } 1231835a0f9STakashi Iwai 1241835a0f9STakashi Iwai void snd_hda_jack_tbl_clear(struct hda_codec *codec) 1251835a0f9STakashi Iwai { 12631ef2257STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 12731ef2257STakashi Iwai int i; 1281a4f69d5STakashi Iwai 12931ef2257STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) { 1301a4f69d5STakashi Iwai struct hda_jack_callback *cb, *next; 1312ba2dfa1SJie Yang 1321a4f69d5STakashi Iwai /* free jack instances manually when clearing/reconfiguring */ 1331a4f69d5STakashi Iwai if (!codec->bus->shutdown && jack->jack) 1346efdd851STakashi Iwai snd_device_free(codec->card, jack->jack); 1352ba2dfa1SJie Yang 1361a4f69d5STakashi Iwai for (cb = jack->callback; cb; cb = next) { 1371a4f69d5STakashi Iwai next = cb->next; 1381a4f69d5STakashi Iwai kfree(cb); 1391a4f69d5STakashi Iwai } 1401a4f69d5STakashi Iwai } 1411835a0f9STakashi Iwai snd_array_free(&codec->jacktbl); 1421835a0f9STakashi Iwai } 1431835a0f9STakashi Iwai 1440619ba8cSDylan Reid #define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) 1450619ba8cSDylan Reid 1461835a0f9STakashi Iwai /* update the cached value and notification flag if needed */ 1471835a0f9STakashi Iwai static void jack_detect_update(struct hda_codec *codec, 1481835a0f9STakashi Iwai struct hda_jack_tbl *jack) 1491835a0f9STakashi Iwai { 15080c8bfbeSDavid Henningsson if (!jack->jack_dirty) 15180c8bfbeSDavid Henningsson return; 15280c8bfbeSDavid Henningsson 15380c8bfbeSDavid Henningsson if (jack->phantom_jack) 15480c8bfbeSDavid Henningsson jack->pin_sense = AC_PINSENSE_PRESENCE; 15580c8bfbeSDavid Henningsson else 15635be544aSTakashi Iwai jack->pin_sense = read_pin_sense(codec, jack->nid); 15780c8bfbeSDavid Henningsson 1580619ba8cSDylan Reid /* A gating jack indicates the jack is invalid if gating is unplugged */ 1590619ba8cSDylan Reid if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack)) 1600619ba8cSDylan Reid jack->pin_sense &= ~AC_PINSENSE_PRESENCE; 1610619ba8cSDylan Reid 1621835a0f9STakashi Iwai jack->jack_dirty = 0; 1630619ba8cSDylan Reid 1640619ba8cSDylan Reid /* If a jack is gated by this one update it. */ 1650619ba8cSDylan Reid if (jack->gated_jack) { 1660619ba8cSDylan Reid struct hda_jack_tbl *gated = 1670619ba8cSDylan Reid snd_hda_jack_tbl_get(codec, jack->gated_jack); 1680619ba8cSDylan Reid if (gated) { 1690619ba8cSDylan Reid gated->jack_dirty = 1; 1700619ba8cSDylan Reid jack_detect_update(codec, gated); 1710619ba8cSDylan Reid } 1720619ba8cSDylan Reid } 1731835a0f9STakashi Iwai } 1741835a0f9STakashi Iwai 1751835a0f9STakashi Iwai /** 1761835a0f9STakashi Iwai * snd_hda_set_dirty_all - Mark all the cached as dirty 177a11e9b16STakashi Iwai * @codec: the HDA codec 1781835a0f9STakashi Iwai * 1791835a0f9STakashi Iwai * This function sets the dirty flag to all entries of jack table. 1801835a0f9STakashi Iwai * It's called from the resume path in hda_codec.c. 1811835a0f9STakashi Iwai */ 1821835a0f9STakashi Iwai void snd_hda_jack_set_dirty_all(struct hda_codec *codec) 1831835a0f9STakashi Iwai { 1841835a0f9STakashi Iwai struct hda_jack_tbl *jack = codec->jacktbl.list; 1851835a0f9STakashi Iwai int i; 1861835a0f9STakashi Iwai 1871835a0f9STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 1881835a0f9STakashi Iwai if (jack->nid) 1891835a0f9STakashi Iwai jack->jack_dirty = 1; 1901835a0f9STakashi Iwai } 1912698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); 1921835a0f9STakashi Iwai 1931835a0f9STakashi Iwai /** 194*80b917a8SNikhil Mahale * snd_hda_jack_pin_sense - execute pin sense measurement 1951835a0f9STakashi Iwai * @codec: the CODEC to sense 1961835a0f9STakashi Iwai * @nid: the pin NID to sense 1971835a0f9STakashi Iwai * 1981835a0f9STakashi Iwai * Execute necessary pin sense measurement and return its Presence Detect, 1991835a0f9STakashi Iwai * Impedance, ELD Valid etc. status bits. 2001835a0f9STakashi Iwai */ 201*80b917a8SNikhil Mahale u32 snd_hda_jack_pin_sense(struct hda_codec *codec, hda_nid_t nid) 2021835a0f9STakashi Iwai { 2031835a0f9STakashi Iwai struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); 2041835a0f9STakashi Iwai if (jack) { 2051835a0f9STakashi Iwai jack_detect_update(codec, jack); 2061835a0f9STakashi Iwai return jack->pin_sense; 2071835a0f9STakashi Iwai } 2081835a0f9STakashi Iwai return read_pin_sense(codec, nid); 2091835a0f9STakashi Iwai } 210*80b917a8SNikhil Mahale EXPORT_SYMBOL_GPL(snd_hda_jack_pin_sense); 2111835a0f9STakashi Iwai 2121835a0f9STakashi Iwai /** 21360ea8ca2STakashi Iwai * snd_hda_jack_detect_state - query pin Presence Detect status 2141835a0f9STakashi Iwai * @codec: the CODEC to sense 2151835a0f9STakashi Iwai * @nid: the pin NID to sense 2161835a0f9STakashi Iwai * 21760ea8ca2STakashi Iwai * Query and return the pin's Presence Detect status, as either 21860ea8ca2STakashi Iwai * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. 2191835a0f9STakashi Iwai */ 22060ea8ca2STakashi Iwai int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) 2211835a0f9STakashi Iwai { 22260ea8ca2STakashi Iwai struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); 22360ea8ca2STakashi Iwai if (jack && jack->phantom_jack) 22460ea8ca2STakashi Iwai return HDA_JACK_PHANTOM; 225*80b917a8SNikhil Mahale else if (snd_hda_jack_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) 22660ea8ca2STakashi Iwai return HDA_JACK_PRESENT; 22760ea8ca2STakashi Iwai else 22860ea8ca2STakashi Iwai return HDA_JACK_NOT_PRESENT; 2291835a0f9STakashi Iwai } 2302698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state); 2311835a0f9STakashi Iwai 2321835a0f9STakashi Iwai /** 2331835a0f9STakashi Iwai * snd_hda_jack_detect_enable - enable the jack-detection 234a11e9b16STakashi Iwai * @codec: the HDA codec 235a11e9b16STakashi Iwai * @nid: pin NID to enable 236a11e9b16STakashi Iwai * @func: callback function to register 237bda17b82STakashi Iwai * 238bda17b82STakashi Iwai * In the case of error, the return value will be a pointer embedded with 239bda17b82STakashi Iwai * errno. Check and handle the return value appropriately with standard 240bda17b82STakashi Iwai * macros such as @IS_ERR() and @PTR_ERR(). 2411835a0f9STakashi Iwai */ 2421a4f69d5STakashi Iwai struct hda_jack_callback * 243bda17b82STakashi Iwai snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, 2441a4f69d5STakashi Iwai hda_jack_callback_fn func) 2451835a0f9STakashi Iwai { 2461a4f69d5STakashi Iwai struct hda_jack_tbl *jack; 2471a4f69d5STakashi Iwai struct hda_jack_callback *callback = NULL; 248bda17b82STakashi Iwai int err; 249bda17b82STakashi Iwai 2501a4f69d5STakashi Iwai jack = snd_hda_jack_tbl_new(codec, nid); 2511835a0f9STakashi Iwai if (!jack) 252bda17b82STakashi Iwai return ERR_PTR(-ENOMEM); 2531a4f69d5STakashi Iwai if (func) { 2541a4f69d5STakashi Iwai callback = kzalloc(sizeof(*callback), GFP_KERNEL); 2551a4f69d5STakashi Iwai if (!callback) 2561a4f69d5STakashi Iwai return ERR_PTR(-ENOMEM); 2571a4f69d5STakashi Iwai callback->func = func; 2582ebab40eSTakashi Iwai callback->nid = jack->nid; 2591a4f69d5STakashi Iwai callback->next = jack->callback; 2601a4f69d5STakashi Iwai jack->callback = callback; 2611a4f69d5STakashi Iwai } 2621a4f69d5STakashi Iwai 2633a93897eSTakashi Iwai if (jack->jack_detect) 2641a4f69d5STakashi Iwai return callback; /* already registered */ 2653a93897eSTakashi Iwai jack->jack_detect = 1; 26634a93187SDavid Henningsson if (codec->jackpoll_interval > 0) 2671a4f69d5STakashi Iwai return callback; /* No unsol if we're polling instead */ 268bda17b82STakashi Iwai err = snd_hda_codec_write_cache(codec, nid, 0, 2691835a0f9STakashi Iwai AC_VERB_SET_UNSOLICITED_ENABLE, 2703a93897eSTakashi Iwai AC_USRSP_EN | jack->tag); 271bda17b82STakashi Iwai if (err < 0) 272bda17b82STakashi Iwai return ERR_PTR(err); 2731a4f69d5STakashi Iwai return callback; 2741835a0f9STakashi Iwai } 2752698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback); 276954df2a9SDavid Henningsson 27795a962c3STakashi Iwai /** 27895a962c3STakashi Iwai * snd_hda_jack_detect_enable - Enable the jack detection on the given pin 27995a962c3STakashi Iwai * @codec: the HDA codec 28095a962c3STakashi Iwai * @nid: pin NID to enable jack detection 28195a962c3STakashi Iwai * 28295a962c3STakashi Iwai * Enable the jack detection with the default callback. Returns zero if 28395a962c3STakashi Iwai * successful or a negative error code. 28495a962c3STakashi Iwai */ 28562f949bfSTakashi Iwai int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid) 286954df2a9SDavid Henningsson { 287bda17b82STakashi Iwai return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback(codec, nid, NULL)); 288954df2a9SDavid Henningsson } 2892698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); 29001a61e12STakashi Iwai 29101a61e12STakashi Iwai /** 2920619ba8cSDylan Reid * snd_hda_jack_set_gating_jack - Set gating jack. 293a11e9b16STakashi Iwai * @codec: the HDA codec 294a11e9b16STakashi Iwai * @gated_nid: gated pin NID 295a11e9b16STakashi Iwai * @gating_nid: gating pin NID 2960619ba8cSDylan Reid * 2970619ba8cSDylan Reid * Indicates the gated jack is only valid when the gating jack is plugged. 2980619ba8cSDylan Reid */ 2990619ba8cSDylan Reid int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, 3000619ba8cSDylan Reid hda_nid_t gating_nid) 3010619ba8cSDylan Reid { 302bde7bc60SChih-Chung Chang struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid); 303bde7bc60SChih-Chung Chang struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid); 3040619ba8cSDylan Reid 3050619ba8cSDylan Reid if (!gated || !gating) 3060619ba8cSDylan Reid return -EINVAL; 3070619ba8cSDylan Reid 3080619ba8cSDylan Reid gated->gating_jack = gating_nid; 3090619ba8cSDylan Reid gating->gated_jack = gated_nid; 3100619ba8cSDylan Reid 3110619ba8cSDylan Reid return 0; 3120619ba8cSDylan Reid } 3132698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); 3140619ba8cSDylan Reid 3150619ba8cSDylan Reid /** 31601a61e12STakashi Iwai * snd_hda_jack_report_sync - sync the states of all jacks and report if changed 317a11e9b16STakashi Iwai * @codec: the HDA codec 31801a61e12STakashi Iwai */ 31901a61e12STakashi Iwai void snd_hda_jack_report_sync(struct hda_codec *codec) 32001a61e12STakashi Iwai { 3210619ba8cSDylan Reid struct hda_jack_tbl *jack; 32235be544aSTakashi Iwai int i, state; 32301a61e12STakashi Iwai 3240619ba8cSDylan Reid /* update all jacks at first */ 3250619ba8cSDylan Reid jack = codec->jacktbl.list; 3260619ba8cSDylan Reid for (i = 0; i < codec->jacktbl.used; i++, jack++) 3270619ba8cSDylan Reid if (jack->nid) 3280619ba8cSDylan Reid jack_detect_update(codec, jack); 3290619ba8cSDylan Reid 3300619ba8cSDylan Reid /* report the updated jacks; it's done after updating all jacks 3310619ba8cSDylan Reid * to make sure that all gating jacks properly have been set 3320619ba8cSDylan Reid */ 3330619ba8cSDylan Reid jack = codec->jacktbl.list; 33401a61e12STakashi Iwai for (i = 0; i < codec->jacktbl.used; i++, jack++) 33501a61e12STakashi Iwai if (jack->nid) { 3362ba2dfa1SJie Yang if (!jack->jack || jack->block_report) 337cfc7c9d3STakashi Iwai continue; 338911761c2STakashi Iwai state = jack->button_state; 339911761c2STakashi Iwai if (get_jack_plug_state(jack->pin_sense)) 340911761c2STakashi Iwai state |= jack->type; 341911761c2STakashi Iwai snd_jack_report(jack->jack, state); 342911761c2STakashi Iwai if (jack->button_state) { 34331ef2257STakashi Iwai snd_jack_report(jack->jack, 344911761c2STakashi Iwai state & ~jack->button_state); 345911761c2STakashi Iwai jack->button_state = 0; /* button released */ 346911761c2STakashi Iwai } 34701a61e12STakashi Iwai } 34801a61e12STakashi Iwai } 3492698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); 35001a61e12STakashi Iwai 35131ef2257STakashi Iwai /* guess the jack type from the pin-config */ 35231ef2257STakashi Iwai static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid) 35331ef2257STakashi Iwai { 35431ef2257STakashi Iwai unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); 35531ef2257STakashi Iwai switch (get_defcfg_device(def_conf)) { 35631ef2257STakashi Iwai case AC_JACK_LINE_OUT: 35731ef2257STakashi Iwai case AC_JACK_SPEAKER: 35831ef2257STakashi Iwai return SND_JACK_LINEOUT; 35931ef2257STakashi Iwai case AC_JACK_HP_OUT: 36031ef2257STakashi Iwai return SND_JACK_HEADPHONE; 36131ef2257STakashi Iwai case AC_JACK_SPDIF_OUT: 36231ef2257STakashi Iwai case AC_JACK_DIG_OTHER_OUT: 36331ef2257STakashi Iwai return SND_JACK_AVOUT; 36431ef2257STakashi Iwai case AC_JACK_MIC_IN: 36531ef2257STakashi Iwai return SND_JACK_MICROPHONE; 36631ef2257STakashi Iwai default: 36731ef2257STakashi Iwai return SND_JACK_LINEIN; 36831ef2257STakashi Iwai } 36931ef2257STakashi Iwai } 37031ef2257STakashi Iwai 37131ef2257STakashi Iwai static void hda_free_jack_priv(struct snd_jack *jack) 37231ef2257STakashi Iwai { 37331ef2257STakashi Iwai struct hda_jack_tbl *jacks = jack->private_data; 37431ef2257STakashi Iwai jacks->nid = 0; 37531ef2257STakashi Iwai jacks->jack = NULL; 37631ef2257STakashi Iwai } 37731ef2257STakashi Iwai 37801a61e12STakashi Iwai /** 37901a61e12STakashi Iwai * snd_hda_jack_add_kctl - Add a kctl for the given pin 380a11e9b16STakashi Iwai * @codec: the HDA codec 381a11e9b16STakashi Iwai * @nid: pin NID to assign 382a11e9b16STakashi Iwai * @name: string name for the jack 383a11e9b16STakashi Iwai * @phantom_jack: flag to deal as a phantom jack 384911761c2STakashi Iwai * @type: jack type bits to be reported, 0 for guessing from pincfg 385911761c2STakashi Iwai * @keymap: optional jack / key mapping 38601a61e12STakashi Iwai * 38701a61e12STakashi Iwai * This assigns a jack-detection kctl to the given pin. The kcontrol 38801a61e12STakashi Iwai * will have the given name and index. 38901a61e12STakashi Iwai */ 390909cadc6STakashi Iwai int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, 391911761c2STakashi Iwai const char *name, bool phantom_jack, 392911761c2STakashi Iwai int type, const struct hda_jack_keymap *keymap) 39301a61e12STakashi Iwai { 39401a61e12STakashi Iwai struct hda_jack_tbl *jack; 395911761c2STakashi Iwai const struct hda_jack_keymap *map; 396911761c2STakashi Iwai int err, state, buttons; 39701a61e12STakashi Iwai 3983a93897eSTakashi Iwai jack = snd_hda_jack_tbl_new(codec, nid); 39901a61e12STakashi Iwai if (!jack) 40001a61e12STakashi Iwai return 0; 4012ba2dfa1SJie Yang if (jack->jack) 40201a61e12STakashi Iwai return 0; /* already created */ 40380c8bfbeSDavid Henningsson 404911761c2STakashi Iwai if (!type) 4052ba2dfa1SJie Yang type = get_input_jack_type(codec, nid); 406911761c2STakashi Iwai 407911761c2STakashi Iwai buttons = 0; 408911761c2STakashi Iwai if (keymap) { 409911761c2STakashi Iwai for (map = keymap; map->type; map++) 410911761c2STakashi Iwai buttons |= map->type; 411911761c2STakashi Iwai } 412911761c2STakashi Iwai 413911761c2STakashi Iwai err = snd_jack_new(codec->card, name, type | buttons, 4142ba2dfa1SJie Yang &jack->jack, true, phantom_jack); 41531ef2257STakashi Iwai if (err < 0) 41631ef2257STakashi Iwai return err; 4172ba2dfa1SJie Yang 4182ba2dfa1SJie Yang jack->phantom_jack = !!phantom_jack; 4192ba2dfa1SJie Yang jack->type = type; 420911761c2STakashi Iwai jack->button_state = 0; 42131ef2257STakashi Iwai jack->jack->private_data = jack; 42231ef2257STakashi Iwai jack->jack->private_free = hda_free_jack_priv; 423911761c2STakashi Iwai if (keymap) { 424911761c2STakashi Iwai for (map = keymap; map->type; map++) 425911761c2STakashi Iwai snd_jack_set_key(jack->jack, map->type, map->key); 426911761c2STakashi Iwai } 427911761c2STakashi Iwai 4282ba2dfa1SJie Yang state = snd_hda_jack_detect(codec, nid); 42931ef2257STakashi Iwai snd_jack_report(jack->jack, state ? jack->type : 0); 4302ba2dfa1SJie Yang 43101a61e12STakashi Iwai return 0; 43201a61e12STakashi Iwai } 4332698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl); 43401a61e12STakashi Iwai 435201e06ffSTakashi Iwai static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, 436b26b5116SDavid Henningsson const struct auto_pin_cfg *cfg, 437b26b5116SDavid Henningsson const char *base_name) 43801a61e12STakashi Iwai { 4393a93897eSTakashi Iwai unsigned int def_conf, conn; 440975cc02aSTakashi Iwai char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 4412ba2dfa1SJie Yang int err; 44280c8bfbeSDavid Henningsson bool phantom_jack; 4433a93897eSTakashi Iwai 44401a61e12STakashi Iwai if (!nid) 44501a61e12STakashi Iwai return 0; 4463a93897eSTakashi Iwai def_conf = snd_hda_codec_get_pincfg(codec, nid); 4473a93897eSTakashi Iwai conn = get_defcfg_connect(def_conf); 44880c8bfbeSDavid Henningsson if (conn == AC_JACK_PORT_NONE) 4493a93897eSTakashi Iwai return 0; 45080c8bfbeSDavid Henningsson phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || 45180c8bfbeSDavid Henningsson !is_jack_detectable(codec, nid); 4523a93897eSTakashi Iwai 4532ba2dfa1SJie Yang if (base_name) 454b26b5116SDavid Henningsson strlcpy(name, base_name, sizeof(name)); 4552ba2dfa1SJie Yang else 4562ba2dfa1SJie Yang snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), NULL); 45780c8bfbeSDavid Henningsson if (phantom_jack) 45880c8bfbeSDavid Henningsson /* Example final name: "Internal Mic Phantom Jack" */ 45980c8bfbeSDavid Henningsson strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); 460911761c2STakashi Iwai err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack, 0, NULL); 4613a93897eSTakashi Iwai if (err < 0) 4623a93897eSTakashi Iwai return err; 46380c8bfbeSDavid Henningsson 46480c8bfbeSDavid Henningsson if (!phantom_jack) 46562f949bfSTakashi Iwai return snd_hda_jack_detect_enable(codec, nid); 46680c8bfbeSDavid Henningsson return 0; 46701a61e12STakashi Iwai } 46801a61e12STakashi Iwai 46901a61e12STakashi Iwai /** 47001a61e12STakashi Iwai * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg 471a11e9b16STakashi Iwai * @codec: the HDA codec 472a11e9b16STakashi Iwai * @cfg: pin config table to parse 47301a61e12STakashi Iwai */ 47401a61e12STakashi Iwai int snd_hda_jack_add_kctls(struct hda_codec *codec, 47501a61e12STakashi Iwai const struct auto_pin_cfg *cfg) 47601a61e12STakashi Iwai { 47701a61e12STakashi Iwai const hda_nid_t *p; 478f46c3296STakashi Iwai int i, err; 47901a61e12STakashi Iwai 480b26b5116SDavid Henningsson for (i = 0; i < cfg->num_inputs; i++) { 481b26b5116SDavid Henningsson /* If we have headphone mics; make sure they get the right name 482b26b5116SDavid Henningsson before grabbed by output pins */ 483b26b5116SDavid Henningsson if (cfg->inputs[i].is_headphone_mic) { 484b26b5116SDavid Henningsson if (auto_cfg_hp_outs(cfg) == 1) 485b26b5116SDavid Henningsson err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0], 486b26b5116SDavid Henningsson cfg, "Headphone Mic"); 487b26b5116SDavid Henningsson else 488b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, 489b26b5116SDavid Henningsson cfg, "Headphone Mic"); 490b26b5116SDavid Henningsson } else 491b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, 492b26b5116SDavid Henningsson NULL); 493b26b5116SDavid Henningsson if (err < 0) 494b26b5116SDavid Henningsson return err; 495b26b5116SDavid Henningsson } 496b26b5116SDavid Henningsson 49701a61e12STakashi Iwai for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { 498b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 49901a61e12STakashi Iwai if (err < 0) 50001a61e12STakashi Iwai return err; 50101a61e12STakashi Iwai } 50201a61e12STakashi Iwai for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { 50301a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 50401a61e12STakashi Iwai break; 505b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 50601a61e12STakashi Iwai if (err < 0) 50701a61e12STakashi Iwai return err; 50801a61e12STakashi Iwai } 50901a61e12STakashi Iwai for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { 51001a61e12STakashi Iwai if (*p == *cfg->line_out_pins) /* might be duplicated */ 51101a61e12STakashi Iwai break; 512b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 51301a61e12STakashi Iwai if (err < 0) 51401a61e12STakashi Iwai return err; 51501a61e12STakashi Iwai } 51601a61e12STakashi Iwai for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { 517b26b5116SDavid Henningsson err = add_jack_kctl(codec, *p, cfg, NULL); 51801a61e12STakashi Iwai if (err < 0) 51901a61e12STakashi Iwai return err; 52001a61e12STakashi Iwai } 521b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL); 52201a61e12STakashi Iwai if (err < 0) 52301a61e12STakashi Iwai return err; 524b26b5116SDavid Henningsson err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL); 52501a61e12STakashi Iwai if (err < 0) 52601a61e12STakashi Iwai return err; 52701a61e12STakashi Iwai return 0; 52801a61e12STakashi Iwai } 5292698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); 530954df2a9SDavid Henningsson 531e6ce180fSTakashi Iwai static void call_jack_callback(struct hda_codec *codec, unsigned int res, 5320619ba8cSDylan Reid struct hda_jack_tbl *jack) 5330619ba8cSDylan Reid { 5341a4f69d5STakashi Iwai struct hda_jack_callback *cb; 5351a4f69d5STakashi Iwai 536e6ce180fSTakashi Iwai for (cb = jack->callback; cb; cb = cb->next) { 537e6ce180fSTakashi Iwai cb->jack = jack; 538e6ce180fSTakashi Iwai cb->unsol_res = res; 5391a4f69d5STakashi Iwai cb->func(codec, cb); 540e6ce180fSTakashi Iwai } 5410619ba8cSDylan Reid if (jack->gated_jack) { 5420619ba8cSDylan Reid struct hda_jack_tbl *gated = 5430619ba8cSDylan Reid snd_hda_jack_tbl_get(codec, jack->gated_jack); 5441a4f69d5STakashi Iwai if (gated) { 545e6ce180fSTakashi Iwai for (cb = gated->callback; cb; cb = cb->next) { 546e6ce180fSTakashi Iwai cb->jack = gated; 547e6ce180fSTakashi Iwai cb->unsol_res = res; 5481a4f69d5STakashi Iwai cb->func(codec, cb); 5491a4f69d5STakashi Iwai } 5500619ba8cSDylan Reid } 5510619ba8cSDylan Reid } 552e6ce180fSTakashi Iwai } 5530619ba8cSDylan Reid 55495a962c3STakashi Iwai /** 55595a962c3STakashi Iwai * snd_hda_jack_unsol_event - Handle an unsolicited event 55695a962c3STakashi Iwai * @codec: the HDA codec 55795a962c3STakashi Iwai * @res: the unsolicited event data 55895a962c3STakashi Iwai */ 559954df2a9SDavid Henningsson void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) 560954df2a9SDavid Henningsson { 561954df2a9SDavid Henningsson struct hda_jack_tbl *event; 562c7e68a69SGuennadi Liakhovetski int tag = (res & AC_UNSOL_RES_TAG) >> AC_UNSOL_RES_TAG_SHIFT; 563954df2a9SDavid Henningsson 564954df2a9SDavid Henningsson event = snd_hda_jack_tbl_get_from_tag(codec, tag); 565954df2a9SDavid Henningsson if (!event) 566954df2a9SDavid Henningsson return; 567954df2a9SDavid Henningsson event->jack_dirty = 1; 568954df2a9SDavid Henningsson 569e6ce180fSTakashi Iwai call_jack_callback(codec, res, event); 570954df2a9SDavid Henningsson snd_hda_jack_report_sync(codec); 571954df2a9SDavid Henningsson } 5722698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); 573954df2a9SDavid Henningsson 57495a962c3STakashi Iwai /** 57595a962c3STakashi Iwai * snd_hda_jack_poll_all - Poll all jacks 57695a962c3STakashi Iwai * @codec: the HDA codec 57795a962c3STakashi Iwai * 57895a962c3STakashi Iwai * Poll all detectable jacks with dirty flag, update the status, call 57995a962c3STakashi Iwai * callbacks and call snd_hda_jack_report_sync() if any changes are found. 58095a962c3STakashi Iwai */ 58126a6cb6cSDavid Henningsson void snd_hda_jack_poll_all(struct hda_codec *codec) 58226a6cb6cSDavid Henningsson { 58326a6cb6cSDavid Henningsson struct hda_jack_tbl *jack = codec->jacktbl.list; 58426a6cb6cSDavid Henningsson int i, changes = 0; 58526a6cb6cSDavid Henningsson 58626a6cb6cSDavid Henningsson for (i = 0; i < codec->jacktbl.used; i++, jack++) { 58726a6cb6cSDavid Henningsson unsigned int old_sense; 58826a6cb6cSDavid Henningsson if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) 58926a6cb6cSDavid Henningsson continue; 59026a6cb6cSDavid Henningsson old_sense = get_jack_plug_state(jack->pin_sense); 59126a6cb6cSDavid Henningsson jack_detect_update(codec, jack); 59226a6cb6cSDavid Henningsson if (old_sense == get_jack_plug_state(jack->pin_sense)) 59326a6cb6cSDavid Henningsson continue; 59426a6cb6cSDavid Henningsson changes = 1; 595e6ce180fSTakashi Iwai call_jack_callback(codec, 0, jack); 59626a6cb6cSDavid Henningsson } 59726a6cb6cSDavid Henningsson if (changes) 59826a6cb6cSDavid Henningsson snd_hda_jack_report_sync(codec); 59926a6cb6cSDavid Henningsson } 6002698ea98STakashi Iwai EXPORT_SYMBOL_GPL(snd_hda_jack_poll_all); 60126a6cb6cSDavid Henningsson 602