Merge branch 'topic/asoc' into for-linus
[pandora-kernel.git] / sound / soc / codecs / wm8350.c
index 2e0772f..8ae2020 100644 (file)
@@ -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);