ALSA: Introduce common helper functions for jack-detection control
[linux-flexiantxendom0.git] / sound / pci / hda / hda_jack.c
1 /*
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 <sound/control.h>
16 #include "hda_codec.h"
17 #include "hda_local.h"
18 #include "hda_jack.h"
19
20 /* execute pin sense measurement */
21 static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
22 {
23         u32 pincap;
24
25         if (!codec->no_trigger_sense) {
26                 pincap = snd_hda_query_pin_caps(codec, nid);
27                 if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */
28                         snd_hda_codec_read(codec, nid, 0,
29                                         AC_VERB_SET_PIN_SENSE, 0);
30         }
31         return snd_hda_codec_read(codec, nid, 0,
32                                   AC_VERB_GET_PIN_SENSE, 0);
33 }
34
35 /**
36  * snd_hda_jack_tbl_get - query the jack-table entry for the given NID
37  */
38 struct hda_jack_tbl *
39 snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
40 {
41         struct hda_jack_tbl *jack = codec->jacktbl.list;
42         int i;
43
44         if (!nid || !jack)
45                 return NULL;
46         for (i = 0; i < codec->jacktbl.used; i++, jack++)
47                 if (jack->nid == nid)
48                         return jack;
49         return NULL;
50 }
51 EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get);
52
53 /**
54  * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag
55  */
56 struct hda_jack_tbl *
57 snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag)
58 {
59         struct hda_jack_tbl *jack = codec->jacktbl.list;
60         int i;
61
62         if (!tag || !jack)
63                 return NULL;
64         for (i = 0; i < codec->jacktbl.used; i++, jack++)
65                 if (jack->tag == tag)
66                         return jack;
67         return NULL;
68 }
69 EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get_from_tag);
70
71 /**
72  * snd_hda_jack_tbl_new - create a jack-table entry for the given NID
73  */
74 struct hda_jack_tbl *
75 snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
76 {
77         struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
78         if (jack)
79                 return jack;
80         snd_array_init(&codec->jacktbl, sizeof(*jack), 16);
81         jack = snd_array_new(&codec->jacktbl);
82         if (!jack)
83                 return NULL;
84         jack->nid = nid;
85         jack->jack_dirty = 1;
86         jack->tag = codec->jacktbl.used;
87         return jack;
88 }
89
90 void snd_hda_jack_tbl_clear(struct hda_codec *codec)
91 {
92         snd_array_free(&codec->jacktbl);
93 }
94
95 /* update the cached value and notification flag if needed */
96 static void jack_detect_update(struct hda_codec *codec,
97                                struct hda_jack_tbl *jack)
98 {
99         if (jack->jack_dirty || !jack->jack_detect) {
100                 jack->pin_sense = read_pin_sense(codec, jack->nid);
101                 jack->jack_dirty = 0;
102         }
103 }
104
105 /**
106  * snd_hda_set_dirty_all - Mark all the cached as dirty
107  *
108  * This function sets the dirty flag to all entries of jack table.
109  * It's called from the resume path in hda_codec.c.
110  */
111 void snd_hda_jack_set_dirty_all(struct hda_codec *codec)
112 {
113         struct hda_jack_tbl *jack = codec->jacktbl.list;
114         int i;
115
116         for (i = 0; i < codec->jacktbl.used; i++, jack++)
117                 if (jack->nid)
118                         jack->jack_dirty = 1;
119 }
120 EXPORT_SYMBOL_HDA(snd_hda_jack_set_dirty_all);
121
122 /**
123  * snd_hda_pin_sense - execute pin sense measurement
124  * @codec: the CODEC to sense
125  * @nid: the pin NID to sense
126  *
127  * Execute necessary pin sense measurement and return its Presence Detect,
128  * Impedance, ELD Valid etc. status bits.
129  */
130 u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
131 {
132         struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
133         if (jack) {
134                 jack_detect_update(codec, jack);
135                 return jack->pin_sense;
136         }
137         return read_pin_sense(codec, nid);
138 }
139 EXPORT_SYMBOL_HDA(snd_hda_pin_sense);
140
141 #define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE)
142
143 /**
144  * snd_hda_jack_detect - query pin Presence Detect status
145  * @codec: the CODEC to sense
146  * @nid: the pin NID to sense
147  *
148  * Query and return the pin's Presence Detect status.
149  */
150 int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
151 {
152         u32 sense = snd_hda_pin_sense(codec, nid);
153         return get_jack_plug_state(sense);
154 }
155 EXPORT_SYMBOL_HDA(snd_hda_jack_detect);
156
157 /**
158  * snd_hda_jack_detect_enable - enable the jack-detection
159  */
160 int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid,
161                                unsigned char action)
162 {
163         struct hda_jack_tbl *jack = snd_hda_jack_tbl_new(codec, nid);
164         if (!jack)
165                 return -ENOMEM;
166         if (jack->jack_detect)
167                 return 0; /* already registered */
168         jack->jack_detect = 1;
169         if (action)
170                 jack->action = action;
171         return snd_hda_codec_write_cache(codec, nid, 0,
172                                          AC_VERB_SET_UNSOLICITED_ENABLE,
173                                          AC_USRSP_EN | jack->tag);
174 }
175 EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable);
176
177 /**
178  * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
179  */
180 void snd_hda_jack_report_sync(struct hda_codec *codec)
181 {
182         struct hda_jack_tbl *jack = codec->jacktbl.list;
183         int i, state;
184
185         for (i = 0; i < codec->jacktbl.used; i++, jack++)
186                 if (jack->nid) {
187                         jack_detect_update(codec, jack);
188                         state = get_jack_plug_state(jack->pin_sense);
189                         snd_kctl_jack_notify(codec->bus->card, jack->kctl, state);
190                 }
191 }
192 EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync);
193
194 /**
195  * snd_hda_jack_add_kctl - Add a kctl for the given pin
196  *
197  * This assigns a jack-detection kctl to the given pin.  The kcontrol
198  * will have the given name and index.
199  */
200 int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
201                           const char *name, int idx)
202 {
203         struct hda_jack_tbl *jack;
204         struct snd_kcontrol *kctl;
205
206         jack = snd_hda_jack_tbl_new(codec, nid);
207         if (!jack)
208                 return 0;
209         if (jack->kctl)
210                 return 0; /* already created */
211         kctl = snd_kctl_jack_new(name, idx, codec);
212         if (!kctl)
213                 return -ENOMEM;
214         if (snd_hda_ctl_add(codec, nid, kctl) < 0)
215                 return -ENOMEM;
216         jack->kctl = kctl;
217         return 0;
218 }
219
220 static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, int idx,
221                          const struct auto_pin_cfg *cfg)
222 {
223         unsigned int def_conf, conn;
224         int err;
225
226         if (!nid)
227                 return 0;
228         if (!is_jack_detectable(codec, nid))
229                 return 0;
230         def_conf = snd_hda_codec_get_pincfg(codec, nid);
231         conn = get_defcfg_connect(def_conf);
232         if (conn != AC_JACK_PORT_COMPLEX)
233                 return 0;
234
235         err = snd_hda_jack_add_kctl(codec, nid,
236                                      snd_hda_get_pin_label(codec, nid, cfg),
237                                      idx);
238         if (err < 0)
239                 return err;
240         return snd_hda_jack_detect_enable(codec, nid, 0);
241 }
242
243 /**
244  * snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg
245  */
246 int snd_hda_jack_add_kctls(struct hda_codec *codec,
247                            const struct auto_pin_cfg *cfg)
248 {
249         const hda_nid_t *p;
250         int i, err;
251
252         for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) {
253                 err = add_jack_kctl(codec, *p, i, cfg);
254                 if (err < 0)
255                         return err;
256         }
257         for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) {
258                 if (*p == *cfg->line_out_pins) /* might be duplicated */
259                         break;
260                 err = add_jack_kctl(codec, *p, i, cfg);
261                 if (err < 0)
262                         return err;
263         }
264         for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) {
265                 if (*p == *cfg->line_out_pins) /* might be duplicated */
266                         break;
267                 err = add_jack_kctl(codec, *p, i, cfg);
268                 if (err < 0)
269                         return err;
270         }
271         for (i = 0; i < cfg->num_inputs; i++) {
272                 err = add_jack_kctl(codec, cfg->inputs[i].pin, 0, cfg);
273                 if (err < 0)
274                         return err;
275         }
276         for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) {
277                 err = add_jack_kctl(codec, *p, i, cfg);
278                 if (err < 0)
279                         return err;
280         }
281         err = add_jack_kctl(codec, cfg->dig_in_pin, 0, cfg);
282         if (err < 0)
283                 return err;
284         err = add_jack_kctl(codec, cfg->mono_out_pin, 0, cfg);
285         if (err < 0)
286                 return err;
287         return 0;
288 }
289 EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls);