From: Matthew Ranostay <mranostay@embeddedalley.com>
To: alsa-devel@alsa-project.org
Cc: Takashi Iwai <tiwai@suse.de>
Subject: [PATCH2/2] hda: Add support for IDT codecs to report jack presence
Date: Mon, 20 Oct 2008 17:40:22 -0400 [thread overview]
Message-ID: <48FCFAC6.8090407@embeddedalley.com> (raw)
Add support for reporting line out, headphone, and microphone jack insertions
via the jack abstraction layer for the Sigmatel/IDT codec family.
Signed-off-by: Matthew Ranostay <mranostay@embeddedalley.com>
---
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index d106ea5..e3a5e7a 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -36,6 +36,7 @@
#include "hda_patch.h"
#include "hda_beep.h"
+#define STAC_INSERT_EVENT 0x10
#define STAC_PWR_EVENT 0x20
#define STAC_HP_EVENT 0x30
#define STAC_VREF_EVENT 0x40
@@ -129,6 +130,17 @@ enum {
STAC_927X_MODELS
};
+struct sigmatel_event {
+ hda_nid_t nid;
+ int data;
+};
+
+struct sigmatel_jack {
+ hda_nid_t nid;
+ int type;
+ struct snd_jack *jack;
+};
+
struct sigmatel_spec {
struct snd_kcontrol_new *mixers[4];
unsigned int num_mixers;
@@ -161,6 +173,12 @@ struct sigmatel_spec {
hda_nid_t *pwr_nids;
hda_nid_t *dac_list;
+ /* jack detection */
+ struct snd_array jacks;
+
+ /* events */
+ struct snd_array events;
+
/* playback */
struct hda_input_mux *mono_mux;
struct hda_input_mux *amp_mux;
@@ -216,9 +234,6 @@ struct sigmatel_spec {
struct hda_pcm pcm_rec[2]; /* PCM information */
- /* jack detection */
- struct snd_jack *jack;
-
/* dynamic controls and input_mux */
struct auto_pin_cfg autocfg;
struct snd_array kctls;
@@ -2458,13 +2473,15 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol
*kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->autocfg;
+ int nid = cfg->hp_pins[cfg->hp_outs - 1];
spec->hp_switch = ucontrol->value.integer.value[0];
/* check to be sure that the ports are upto date with
* switch changes
*/
- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+ codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26);
return 1;
}
@@ -2504,7 +2521,8 @@ static int stac92xx_io_switch_put(struct snd_kcontrol
*kcontrol, struct snd_ctl_
* appropriately according to the pin direction
*/
if (spec->hp_detect)
- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+ codec->patch_ops.unsol_event(codec,
+ (STAC_HP_EVENT | nid) << 26);
return 1;
}
@@ -3574,13 +3592,70 @@ static void stac_gpio_set(struct hda_codec *codec,
unsigned int mask,
AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
}
+static int stac92xx_add_jack(struct hda_codec *codec,
+ hda_nid_t nid, int type)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct sigmatel_jack *jack;
+ int def_conf = snd_hda_codec_read(codec, nid,
+ 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
+ int connectivity = get_defcfg_connect(def_conf);
+ char name[32];
+
+ if (connectivity && connectivity != AC_JACK_PORT_FIXED)
+ return 0;
+
+ snd_array_init(&spec->jacks, sizeof(*jack), 32);
+ jack = snd_array_new(&spec->jacks);
+ if (!jack)
+ return -ENOMEM;
+ jack->nid = nid;
+ jack->type = type;
+
+ sprintf(name, "%s at %s %s Jack",
+ get_jack_type(def_conf),
+ get_jack_connectivity(def_conf),
+ get_jack_location(def_conf));
+
+ return snd_jack_new(codec->bus->card, name, type, &jack->jack);
+}
+
+static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
+ int data)
+{
+ struct sigmatel_event *event;
+
+ snd_array_init(&spec->events, sizeof(*event), 32);
+ event = snd_array_new(&spec->events);
+ if (!event)
+ return -ENOMEM;
+ event->nid = nid;
+ event->data = data;
+
+ return 0;
+}
+
+static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct sigmatel_event *events = spec->events.list;
+ if (events) {
+ int i;
+ for (i = 0; i < spec->events.used; i++)
+ if (events[i].nid == nid)
+ return events[i].data;
+ }
+ return 0;
+}
+
static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
unsigned int event)
{
- if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)
+ if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
snd_hda_codec_write_cache(codec, nid, 0,
AC_VERB_SET_UNSOLICITED_ENABLE,
- (AC_USRSP_EN | event));
+ (AC_USRSP_EN | event | nid));
+ }
}
static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
@@ -3623,27 +3698,34 @@ static int stac92xx_init(struct hda_codec *codec)
/* set up pins */
if (spec->hp_detect) {
/* Enable unsolicited responses on the HP widget */
- for (i = 0; i < cfg->hp_outs; i++)
- enable_pin_detect(codec, cfg->hp_pins[i],
- STAC_HP_EVENT);
+ for (i = 0; i < cfg->hp_outs; i++) {
+ hda_nid_t nid = cfg->hp_pins[i];
+ enable_pin_detect(codec, nid, STAC_HP_EVENT | nid);
+ /* jack detection */
+ err = stac92xx_add_jack(codec, nid, cfg->hp_outs == i
+ ? SND_JACK_SWITCH : SND_JACK_HEADPHONE);
+ if (err < 0)
+ return err;
+
+ }
/* force to enable the first line-out; the others are set up
* in unsol_event
*/
stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
- AC_PINCTL_OUT_EN);
- stac92xx_auto_init_hp_out(codec);
- /* jack detection */
- err = snd_jack_new(codec->bus->card,
- "Headphone Jack",
- SND_JACK_HEADPHONE, &spec->jack);
- if (err < 0)
- return err;
+ AC_PINCTL_OUT_EN);
/* fake event to set up pins */
- codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26);
+ codec->patch_ops.unsol_event(codec,
+ (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26);
} else {
stac92xx_auto_init_multi_out(codec);
stac92xx_auto_init_hp_out(codec);
}
+ for (i = 0; i < cfg->line_outs; i++) {
+ err = stac92xx_add_jack(codec,
+ cfg->line_out_pins[i], SND_JACK_LINEOUT);
+ if (err < 0)
+ return err;
+ }
for (i = 0; i < AUTO_PIN_LAST; i++) {
hda_nid_t nid = cfg->input_pins[i];
if (nid) {
@@ -3656,6 +3738,11 @@ static int stac92xx_init(struct hda_codec *codec)
if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
pinctl |= stac92xx_get_vref(codec, nid);
stac92xx_auto_set_pinctl(codec, nid, pinctl);
+ err = stac92xx_add_jack(codec, nid,
+ SND_JACK_MICROPHONE);
+ if (err < 0)
+ return err;
+ enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid);
}
}
for (i = 0; i < spec->num_dmics; i++)
@@ -3697,6 +3784,18 @@ static int stac92xx_init(struct hda_codec *codec)
return 0;
}
+static void stac92xx_free_jacks(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ if (spec->jacks.list) {
+ struct sigmatel_jack *jacks = spec->jacks.list;
+ int i;
+ for (i = 0; i < spec->jacks.used; i++)
+ snd_device_free(codec->bus->card, &jacks[i].jack);
+ }
+ snd_array_free(&spec->jacks);
+}
+
static void stac92xx_free_kctls(struct hda_codec *codec)
{
struct sigmatel_spec *spec = codec->spec;
@@ -3717,11 +3816,10 @@ static void stac92xx_free(struct hda_codec *codec)
if (! spec)
return;
- if (spec->jack)
- snd_device_free(codec->bus->card, spec->jack);
-
if (spec->bios_pin_configs)
kfree(spec->bios_pin_configs);
+ stac92xx_free_jacks(codec);
+ snd_array_free(&spec->events);
kfree(spec);
snd_hda_detach_beep_device(codec);
@@ -3804,8 +3902,6 @@ static void stac92xx_hp_detect(struct hda_codec *codec,
unsigned int res)
break;
presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
}
- snd_jack_report(spec->jack,
- presence ? SND_JACK_HEADPHONE : 0);
if (presence) {
/* disable lineouts, enable hp */
@@ -3862,24 +3958,56 @@ static void stac92xx_pin_sense(struct hda_codec *codec,
int idx)
/* power down unused output ports */
snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
-};
+}
+
+static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct sigmatel_jack *jacks = spec->jacks.list;
+
+ if (jacks) {
+ int i;
+ for (i = 0; i < spec->jacks.used; i++) {
+ if (jacks->nid == nid) {
+ unsigned int pin_ctl =
+ snd_hda_codec_read(codec, nid,
+ 0, AC_VERB_GET_PIN_WIDGET_CONTROL,
+ 0x00);
+ int type = jacks->type;
+ if (type == SND_JACK_SWITCH)
+ type = (pin_ctl & AC_PINCTL_HP_EN)
+ ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
+ snd_jack_report(jacks->jack,
+ get_hp_pin_presence(codec, nid)
+ ? type : 0);
+ }
+ jacks++;
+ }
+ }
+}
static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
{
struct sigmatel_spec *spec = codec->spec;
- int idx = res >> 26 & 0x0f;
+ int event = (res >> 26) & 0x70;
+ int nid = res >> 26 & 0x0f;
- switch ((res >> 26) & 0x70) {
+ switch (event) {
case STAC_HP_EVENT:
stac92xx_hp_detect(codec, res);
/* fallthru */
+ case STAC_INSERT_EVENT:
case STAC_PWR_EVENT:
- if (spec->num_pwrs > 0)
- stac92xx_pin_sense(codec, idx);
+ if (nid) {
+ if (spec->num_pwrs > 0)
+ stac92xx_pin_sense(codec, nid);
+ stac92xx_report_jack(codec, nid);
+ }
break;
case STAC_VREF_EVENT: {
int data = snd_hda_codec_read(codec, codec->afg, 0,
AC_VERB_GET_GPIO_DATA, 0);
+ int idx = stac92xx_event_data(codec, nid);
/* toggle VREF state based on GPIOx status */
snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
!!(data & (1 << idx)));
@@ -4402,8 +4530,11 @@ again:
snd_hda_codec_write(codec, codec->afg, 0,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
snd_hda_codec_write_cache(codec, codec->afg, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- (AC_USRSP_EN | STAC_VREF_EVENT | 0x01));
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
+ err = stac92xx_add_event(spec, codec->afg, 0x02);
+ if (err < 0)
+ return err;
spec->gpio_mask |= 0x02;
break;
}
@@ -4802,8 +4933,11 @@ static int patch_stac9205(struct hda_codec *codec)
snd_hda_codec_write(codec, codec->afg, 0,
AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
snd_hda_codec_write_cache(codec, codec->afg, 0,
- AC_VERB_SET_UNSOLICITED_ENABLE,
- (AC_USRSP_EN | STAC_HP_EVENT));
+ AC_VERB_SET_UNSOLICITED_ENABLE,
+ (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
+ err = stac92xx_add_event(spec, codec->afg, 0x01);
+ if (err < 0)
+ return err;
spec->gpio_dir = 0x0b;
spec->eapd_mask = 0x01;
next reply other threads:[~2008-10-20 21:40 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-10-20 21:40 Matthew Ranostay [this message]
2008-10-21 8:55 ` [PATCH2/2] hda: Add support for IDT codecs to report jack presence Mark Brown
2008-10-21 15:20 ` Matthew Ranostay
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48FCFAC6.8090407@embeddedalley.com \
--to=mranostay@embeddedalley.com \
--cc=alsa-devel@alsa-project.org \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.