diff options
Diffstat (limited to 'sound/soc/codecs/wm8350.c')
-rw-r--r-- | sound/soc/codecs/wm8350.c | 103 |
1 files changed, 84 insertions, 19 deletions
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 2e0772f9c456..8ae20208e7be 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -55,6 +55,7 @@ struct wm8350_output { struct wm8350_jack_data { struct snd_soc_jack *jack; int report; + int short_report; }; struct wm8350_data { @@ -63,6 +64,7 @@ struct wm8350_data { struct wm8350_output out2; struct wm8350_jack_data hpl; struct wm8350_jack_data hpr; + struct wm8350_jack_data mic; struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; int fll_freq_out; int fll_freq_in; @@ -94,7 +96,7 @@ static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg, */ static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec) { - struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out1 = &wm8350_data->out1; struct wm8350 *wm8350 = codec->control_data; int left_complete = 0, right_complete = 0; @@ -160,7 +162,7 @@ static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec) */ static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec) { - struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out2 = &wm8350_data->out2; struct wm8350 *wm8350 = codec->control_data; int left_complete = 0, right_complete = 0; @@ -230,7 +232,7 @@ static void wm8350_pga_work(struct work_struct *work) { struct snd_soc_codec *codec = container_of(work, struct snd_soc_codec, delayed_work.work); - struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out1 = &wm8350_data->out1, *out2 = &wm8350_data->out2; int i, out1_complete, out2_complete; @@ -277,7 +279,7 @@ static int pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - struct wm8350_data *wm8350_data = codec->private_data; + struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out; switch (w->shift) { @@ -322,7 +324,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8350_data *wm8350_priv = codec->private_data; + struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out = NULL; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -365,7 +367,7 @@ static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct wm8350_data *wm8350_priv = codec->private_data; + struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec); struct wm8350_output *out1 = &wm8350_priv->out1; struct wm8350_output *out2 = &wm8350_priv->out2; struct soc_mixer_control *mc = @@ -1107,7 +1109,7 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; struct wm8350 *wm8350 = codec->control_data; - struct wm8350_data *priv = codec->private_data; + struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); struct _fll_div fll_div; int ret = 0; u16 fll_1, fll_4; @@ -1159,7 +1161,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { struct wm8350 *wm8350 = codec->control_data; - struct wm8350_data *priv = codec->private_data; + struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); struct wm8350_audio_platform_data *platform = wm8350->codec.platform_data; u16 pm1; @@ -1335,9 +1337,6 @@ static int wm8350_resume(struct platform_device *pdev) wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - if (codec->suspend_bias_level == SND_SOC_BIAS_ON) - wm8350_set_bias_level(codec, SND_SOC_BIAS_ON); - return 0; } @@ -1392,12 +1391,13 @@ static irqreturn_t wm8350_hp_jack_handler(int irq, void *data) * @jack: jack to report detection events on * @report: value to report * - * Enables the headphone jack detection of the WM8350. + * Enables the headphone jack detection of the WM8350. If no report + * is specified then detection is disabled. */ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, struct snd_soc_jack *jack, int report) { - struct wm8350_data *priv = codec->private_data; + struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); struct wm8350 *wm8350 = codec->control_data; int irq; int ena; @@ -1421,8 +1421,12 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, return -EINVAL; } - wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); - wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); + if (report) { + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); + wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); + } else { + wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, ena); + } /* Sync status */ wm8350_hp_jack_handler(irq + wm8350->irq_base, priv); @@ -1431,6 +1435,60 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, } EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect); +static irqreturn_t wm8350_mic_handler(int irq, void *data) +{ + struct wm8350_data *priv = data; + struct wm8350 *wm8350 = priv->codec.control_data; + u16 reg; + int report = 0; + + reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS); + if (reg & WM8350_JACK_MICSCD_LVL) + report |= priv->mic.short_report; + if (reg & WM8350_JACK_MICSD_LVL) + report |= priv->mic.report; + + snd_soc_jack_report(priv->mic.jack, report, + priv->mic.report | priv->mic.short_report); + + return IRQ_HANDLED; +} + +/** + * wm8350_mic_jack_detect - Enable microphone jack detection. + * + * @codec: WM8350 codec + * @jack: jack to report detection events on + * @detect_report: value to report when presence detected + * @short_report: value to report when microphone short detected + * + * Enables the microphone jack detection of the WM8350. If both reports + * are specified as zero then detection is disabled. + */ +int wm8350_mic_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, + int detect_report, int short_report) +{ + struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); + struct wm8350 *wm8350 = codec->control_data; + + priv->mic.jack = jack; + priv->mic.report = detect_report; + priv->mic.short_report = short_report; + + if (detect_report || short_report) { + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); + wm8350_set_bits(wm8350, WM8350_POWER_MGMT_1, + WM8350_MIC_DET_ENA); + } else { + wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_1, + WM8350_MIC_DET_ENA); + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect); + static struct snd_soc_codec *wm8350_codec; static int wm8350_probe(struct platform_device *pdev) @@ -1448,7 +1506,7 @@ static int wm8350_probe(struct platform_device *pdev) socdev->card->codec = wm8350_codec; codec = socdev->card->codec; wm8350 = codec->control_data; - priv = codec->private_data; + priv = snd_soc_codec_get_drvdata(codec); /* Enable the codec */ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); @@ -1494,6 +1552,10 @@ static int wm8350_probe(struct platform_device *pdev) wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, wm8350_hp_jack_handler, 0, "Right jack detect", priv); + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, + wm8350_mic_handler, 0, "Microphone short", priv); + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, + wm8350_mic_handler, 0, "Microphone detect", priv); ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { @@ -1515,18 +1577,21 @@ static int wm8350_remove(struct platform_device *pdev) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; struct wm8350 *wm8350 = codec->control_data; - struct wm8350_data *priv = codec->private_data; + struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); int ret; wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, WM8350_JDL_ENA | WM8350_JDR_ENA); wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICD, priv); + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv); wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv); wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv); priv->hpl.jack = NULL; priv->hpr.jack = NULL; + priv->mic.jack = NULL; /* cancel any work waiting to be queued. */ ret = cancel_delayed_work(&codec->delayed_work); @@ -1631,7 +1696,7 @@ static __devinit int wm8350_codec_probe(struct platform_device *pdev) codec->dai = &wm8350_dai; codec->num_dai = 1; codec->reg_cache_size = WM8350_MAX_REGISTER; - codec->private_data = priv; + snd_soc_codec_set_drvdata(codec, priv); codec->control_data = wm8350; /* Put the codec into reset if it wasn't already */ @@ -1663,7 +1728,7 @@ static int __devexit wm8350_codec_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct snd_soc_codec *codec = wm8350->codec.codec; - struct wm8350_data *priv = codec->private_data; + struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); snd_soc_unregister_dai(&wm8350_dai); snd_soc_unregister_codec(codec); |