| Index: sound/soc/codecs/wm8350.c
|
| diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
|
| index 7611add7f8c38751806684a521d891ede746197f..6d6dc9efe9145d0f044d4e39762f52c9a9aca2af 100644
|
| --- a/sound/soc/codecs/wm8350.c
|
| +++ b/sound/soc/codecs/wm8350.c
|
| @@ -24,9 +24,9 @@
|
| #include <sound/pcm.h>
|
| #include <sound/pcm_params.h>
|
| #include <sound/soc.h>
|
| -#include <sound/soc-dapm.h>
|
| #include <sound/initval.h>
|
| #include <sound/tlv.h>
|
| +#include <trace/events/asoc.h>
|
|
|
| #include "wm8350.h"
|
|
|
| @@ -54,6 +54,7 @@ struct wm8350_output {
|
|
|
| struct wm8350_jack_data {
|
| struct snd_soc_jack *jack;
|
| + struct delayed_work work;
|
| int report;
|
| int short_report;
|
| };
|
| @@ -230,8 +231,9 @@ static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec)
|
| */
|
| 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 snd_soc_dapm_context *dapm =
|
| + container_of(work, struct snd_soc_dapm_context, delayed_work.work);
|
| + struct snd_soc_codec *codec = dapm->codec;
|
| struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
|
| struct wm8350_output *out1 = &wm8350_data->out1,
|
| *out2 = &wm8350_data->out2;
|
| @@ -302,8 +304,8 @@ static int pga_event(struct snd_soc_dapm_widget *w,
|
| out->ramp = WM8350_RAMP_UP;
|
| out->active = 1;
|
|
|
| - if (!delayed_work_pending(&codec->delayed_work))
|
| - schedule_delayed_work(&codec->delayed_work,
|
| + if (!delayed_work_pending(&codec->dapm.delayed_work))
|
| + schedule_delayed_work(&codec->dapm.delayed_work,
|
| msecs_to_jiffies(1));
|
| break;
|
|
|
| @@ -311,8 +313,8 @@ static int pga_event(struct snd_soc_dapm_widget *w,
|
| out->ramp = WM8350_RAMP_DOWN;
|
| out->active = 0;
|
|
|
| - if (!delayed_work_pending(&codec->delayed_work))
|
| - schedule_delayed_work(&codec->delayed_work,
|
| + if (!delayed_work_pending(&codec->dapm.delayed_work))
|
| + schedule_delayed_work(&codec->dapm.delayed_work,
|
| msecs_to_jiffies(1));
|
| break;
|
| }
|
| @@ -786,9 +788,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
|
|
|
| static int wm8350_add_widgets(struct snd_soc_codec *codec)
|
| {
|
| + struct snd_soc_dapm_context *dapm = &codec->dapm;
|
| int ret;
|
|
|
| - ret = snd_soc_dapm_new_controls(codec,
|
| + ret = snd_soc_dapm_new_controls(dapm,
|
| wm8350_dapm_widgets,
|
| ARRAY_SIZE(wm8350_dapm_widgets));
|
| if (ret != 0) {
|
| @@ -797,7 +800,7 @@ static int wm8350_add_widgets(struct snd_soc_codec *codec)
|
| }
|
|
|
| /* set up audio paths */
|
| - ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
|
| + ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
|
| if (ret != 0) {
|
| dev_err(codec->dev, "DAPM route register failed\n");
|
| return ret;
|
| @@ -1184,7 +1187,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
|
| break;
|
|
|
| case SND_SOC_BIAS_STANDBY:
|
| - if (codec->bias_level == SND_SOC_BIAS_OFF) {
|
| + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
|
| ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
|
| priv->supplies);
|
| if (ret != 0)
|
| @@ -1317,7 +1320,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
|
| priv->supplies);
|
| break;
|
| }
|
| - codec->bias_level = level;
|
| + codec->dapm.bias_level = level;
|
| return 0;
|
| }
|
|
|
| @@ -1334,45 +1337,69 @@ static int wm8350_resume(struct snd_soc_codec *codec)
|
| return 0;
|
| }
|
|
|
| -static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
|
| +static void wm8350_hp_work(struct wm8350_data *priv,
|
| + struct wm8350_jack_data *jack,
|
| + u16 mask)
|
| {
|
| - struct wm8350_data *priv = data;
|
| struct wm8350 *wm8350 = priv->codec.control_data;
|
| u16 reg;
|
| int report;
|
| - int mask;
|
| +
|
| + reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
|
| + if (reg & mask)
|
| + report = jack->report;
|
| + else
|
| + report = 0;
|
| +
|
| + snd_soc_jack_report(jack->jack, report, jack->report);
|
| +
|
| +}
|
| +
|
| +static void wm8350_hpl_work(struct work_struct *work)
|
| +{
|
| + struct wm8350_data *priv =
|
| + container_of(work, struct wm8350_data, hpl.work.work);
|
| +
|
| + wm8350_hp_work(priv, &priv->hpl, WM8350_JACK_L_LVL);
|
| +}
|
| +
|
| +static void wm8350_hpr_work(struct work_struct *work)
|
| +{
|
| + struct wm8350_data *priv =
|
| + container_of(work, struct wm8350_data, hpr.work.work);
|
| +
|
| + wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL);
|
| +}
|
| +
|
| +static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
|
| +{
|
| + struct wm8350_data *priv = data;
|
| + struct wm8350 *wm8350 = priv->codec.control_data;
|
| struct wm8350_jack_data *jack = NULL;
|
|
|
| switch (irq - wm8350->irq_base) {
|
| case WM8350_IRQ_CODEC_JCK_DET_L:
|
| +#ifndef CONFIG_SND_SOC_WM8350_MODULE
|
| + trace_snd_soc_jack_irq("WM8350 HPL");
|
| +#endif
|
| jack = &priv->hpl;
|
| - mask = WM8350_JACK_L_LVL;
|
| break;
|
|
|
| case WM8350_IRQ_CODEC_JCK_DET_R:
|
| +#ifndef CONFIG_SND_SOC_WM8350_MODULE
|
| + trace_snd_soc_jack_irq("WM8350 HPR");
|
| +#endif
|
| jack = &priv->hpr;
|
| - mask = WM8350_JACK_R_LVL;
|
| break;
|
|
|
| default:
|
| BUG();
|
| }
|
|
|
| - if (!jack->jack) {
|
| - dev_warn(wm8350->dev, "Jack interrupt called with no jack\n");
|
| - return IRQ_NONE;
|
| - }
|
| -
|
| - /* Debounce */
|
| - msleep(200);
|
| -
|
| - reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
|
| - if (reg & mask)
|
| - report = jack->report;
|
| - else
|
| - report = 0;
|
| + if (device_may_wakeup(wm8350->dev))
|
| + pm_wakeup_event(wm8350->dev, 250);
|
|
|
| - snd_soc_jack_report(jack->jack, report, jack->report);
|
| + schedule_delayed_work(&jack->work, 200);
|
|
|
| return IRQ_HANDLED;
|
| }
|
| @@ -1436,6 +1463,10 @@ static irqreturn_t wm8350_mic_handler(int irq, void *data)
|
| u16 reg;
|
| int report = 0;
|
|
|
| +#ifndef CONFIG_SND_SOC_WM8350_MODULE
|
| + trace_snd_soc_jack_irq("WM8350 mic");
|
| +#endif
|
| +
|
| reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
|
| if (reg & WM8350_JACK_MICSCD_LVL)
|
| report |= priv->mic.short_report;
|
| @@ -1550,7 +1581,9 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
|
| /* Put the codec into reset if it wasn't already */
|
| wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
|
|
|
| - INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
|
| + INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8350_pga_work);
|
| + INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work);
|
| + INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work);
|
|
|
| /* Enable the codec */
|
| wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
|
| @@ -1626,7 +1659,6 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec)
|
| {
|
| struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
|
| struct wm8350 *wm8350 = dev_get_platdata(codec->dev);
|
| - int ret;
|
|
|
| wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
|
| WM8350_JDL_ENA | WM8350_JDR_ENA);
|
| @@ -1641,15 +1673,12 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec)
|
| priv->hpr.jack = NULL;
|
| priv->mic.jack = NULL;
|
|
|
| - /* cancel any work waiting to be queued. */
|
| - ret = cancel_delayed_work(&codec->delayed_work);
|
| + cancel_delayed_work_sync(&priv->hpl.work);
|
| + cancel_delayed_work_sync(&priv->hpr.work);
|
|
|
| /* if there was any work waiting then we run it now and
|
| * wait for its completion */
|
| - if (ret) {
|
| - schedule_delayed_work(&codec->delayed_work, 0);
|
| - flush_scheduled_work();
|
| - }
|
| + flush_delayed_work_sync(&codec->dapm.delayed_work);
|
|
|
| wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
|
|
|
|