blob: 64b78a2e20e0d4c368f5597ddb8770f22e113e98 [file] [log] [blame]
Takashi Iwai1835a0f2011-10-27 22:12:46 +02001/*
2 * Jack-detection handling for HD-audio
3 *
4 * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de>
5 *
6 * This driver is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#include <linux/init.h>
13#include <linux/slab.h>
14#include <sound/core.h>
15#include "hda_codec.h"
16#include "hda_local.h"
17#include "hda_jack.h"
18
19/* execute pin sense measurement */
20static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
21{
22 u32 pincap;
23
24 if (!codec->no_trigger_sense) {
25 pincap = snd_hda_query_pin_caps(codec, nid);
26 if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
27 snd_hda_codec_read(codec, nid, 0,
28 AC_VERB_SET_PIN_SENSE, 0);
29 }
30 return snd_hda_codec_read(codec, nid, 0,
31 AC_VERB_GET_PIN_SENSE, 0);
32}
33
34/**
35 * snd_hda_jack_tbl_get - query the jack-table entry for the given NID
36 */
37struct hda_jack_tbl *
38snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
39{
40 struct hda_jack_tbl *jack = codec->jacktbl.list;
41 int i;
42
43 if (!nid || !jack)
44 return NULL;
45 for (i = 0; i < codec->jacktbl.used; i++, jack++)
46 if (jack->nid == nid)
47 return jack;
48 return NULL;
49}
50EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get);
51
52/**
53 * snd_hda_jack_tbl_new - create a jack-table entry for the given NID
54 */
55struct hda_jack_tbl *
56snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
57{
58 struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
59 if (jack)
60 return jack;
61 snd_array_init(&codec->jacktbl, sizeof(*jack), 16);
62 jack = snd_array_new(&codec->jacktbl);
63 if (!jack)
64 return NULL;
65 jack->nid = nid;
66 jack->jack_dirty = 1;
67 return jack;
68}
69
70void snd_hda_jack_tbl_clear(struct hda_codec *codec)
71{
72 snd_array_free(&codec->jacktbl);
73}
74
75/* update the cached value and notification flag if needed */
76static void jack_detect_update(struct hda_codec *codec,
77 struct hda_jack_tbl *jack)
78{
79 if (jack->jack_dirty) {
80 jack->pin_sense = read_pin_sense(codec, jack->nid);
81 jack->jack_dirty = 0;
82 }
83}
84
85/**
86 * snd_hda_set_dirty_all - Mark all the cached as dirty
87 *
88 * This function sets the dirty flag to all entries of jack table.
89 * It's called from the resume path in hda_codec.c.
90 */
91void snd_hda_jack_set_dirty_all(struct hda_codec *codec)
92{
93 struct hda_jack_tbl *jack = codec->jacktbl.list;
94 int i;
95
96 for (i = 0; i < codec->jacktbl.used; i++, jack++)
97 if (jack->nid)
98 jack->jack_dirty = 1;
99}
100EXPORT_SYMBOL_HDA(snd_hda_jack_set_dirty_all);
101
102/**
103 * snd_hda_pin_sense - execute pin sense measurement
104 * @codec: the CODEC to sense
105 * @nid: the pin NID to sense
106 *
107 * Execute necessary pin sense measurement and return its Presence Detect,
108 * Impedance, ELD Valid etc. status bits.
109 */
110u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
111{
112 struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
113 if (jack) {
114 jack_detect_update(codec, jack);
115 return jack->pin_sense;
116 }
117 return read_pin_sense(codec, nid);
118}
119EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
120
121/**
122 * snd_hda_jack_detect - query pin Presence Detect status
123 * @codec: the CODEC to sense
124 * @nid: the pin NID to sense
125 *
126 * Query and return the pin's Presence Detect status.
127 */
128int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
129{
130 u32 sense = snd_hda_pin_sense(codec, nid);
131 return !!(sense & AC_PINSENSE_PRESENCE);
132}
133EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
134
135/**
136 * snd_hda_jack_detect_enable - enable the jack-detection
137 */
138int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
139 unsigned int tag)
140{
141 struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
142 if (!jack)
143 return -ENOMEM;
144 return snd_hda_codec_write_cache(codec, nid, 0,
145 AC_VERB_SET_UNSOLICITED_ENABLE,
146 AC_USRSP_EN | tag);
147}
148EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);