Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 293209
b: refs/heads/master
c: 46c1a87
h: refs/heads/master
i:
  293207: d514a34
v: v3
  • Loading branch information
Mark Brown committed Jan 20, 2012
1 parent c82bd4b commit 7911857
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 81 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 218240e27f89b477564a638ff77d45147e42a8fd
refs/heads/master: 46c1a877c6fc29519760a3aaedf807332cd8a781
188 changes: 108 additions & 80 deletions trunk/sound/soc/codecs/wm5100.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct wm5100_fll {

/* codec private data */
struct wm5100_priv {
struct device *dev;
struct regmap *regmap;
struct snd_soc_codec *codec;

Expand Down Expand Up @@ -855,65 +856,66 @@ static int wm5100_dbvdd_ev(struct snd_soc_dapm_widget *w,
}
}

static void wm5100_log_status3(struct snd_soc_codec *codec, int val)
static void wm5100_log_status3(struct wm5100_priv *wm5100, int val)
{
if (val & WM5100_SPK_SHUTDOWN_WARN_EINT)
dev_crit(codec->dev, "Speaker shutdown warning\n");
dev_crit(wm5100->dev, "Speaker shutdown warning\n");
if (val & WM5100_SPK_SHUTDOWN_EINT)
dev_crit(codec->dev, "Speaker shutdown\n");
dev_crit(wm5100->dev, "Speaker shutdown\n");
if (val & WM5100_CLKGEN_ERR_EINT)
dev_crit(codec->dev, "SYSCLK underclocked\n");
dev_crit(wm5100->dev, "SYSCLK underclocked\n");
if (val & WM5100_CLKGEN_ERR_ASYNC_EINT)
dev_crit(codec->dev, "ASYNCCLK underclocked\n");
dev_crit(wm5100->dev, "ASYNCCLK underclocked\n");
}

static void wm5100_log_status4(struct snd_soc_codec *codec, int val)
static void wm5100_log_status4(struct wm5100_priv *wm5100, int val)
{
if (val & WM5100_AIF3_ERR_EINT)
dev_err(codec->dev, "AIF3 configuration error\n");
dev_err(wm5100->dev, "AIF3 configuration error\n");
if (val & WM5100_AIF2_ERR_EINT)
dev_err(codec->dev, "AIF2 configuration error\n");
dev_err(wm5100->dev, "AIF2 configuration error\n");
if (val & WM5100_AIF1_ERR_EINT)
dev_err(codec->dev, "AIF1 configuration error\n");
dev_err(wm5100->dev, "AIF1 configuration error\n");
if (val & WM5100_CTRLIF_ERR_EINT)
dev_err(codec->dev, "Control interface error\n");
dev_err(wm5100->dev, "Control interface error\n");
if (val & WM5100_ISRC2_UNDERCLOCKED_EINT)
dev_err(codec->dev, "ISRC2 underclocked\n");
dev_err(wm5100->dev, "ISRC2 underclocked\n");
if (val & WM5100_ISRC1_UNDERCLOCKED_EINT)
dev_err(codec->dev, "ISRC1 underclocked\n");
dev_err(wm5100->dev, "ISRC1 underclocked\n");
if (val & WM5100_FX_UNDERCLOCKED_EINT)
dev_err(codec->dev, "FX underclocked\n");
dev_err(wm5100->dev, "FX underclocked\n");
if (val & WM5100_AIF3_UNDERCLOCKED_EINT)
dev_err(codec->dev, "AIF3 underclocked\n");
dev_err(wm5100->dev, "AIF3 underclocked\n");
if (val & WM5100_AIF2_UNDERCLOCKED_EINT)
dev_err(codec->dev, "AIF2 underclocked\n");
dev_err(wm5100->dev, "AIF2 underclocked\n");
if (val & WM5100_AIF1_UNDERCLOCKED_EINT)
dev_err(codec->dev, "AIF1 underclocked\n");
dev_err(wm5100->dev, "AIF1 underclocked\n");
if (val & WM5100_ASRC_UNDERCLOCKED_EINT)
dev_err(codec->dev, "ASRC underclocked\n");
dev_err(wm5100->dev, "ASRC underclocked\n");
if (val & WM5100_DAC_UNDERCLOCKED_EINT)
dev_err(codec->dev, "DAC underclocked\n");
dev_err(wm5100->dev, "DAC underclocked\n");
if (val & WM5100_ADC_UNDERCLOCKED_EINT)
dev_err(codec->dev, "ADC underclocked\n");
dev_err(wm5100->dev, "ADC underclocked\n");
if (val & WM5100_MIXER_UNDERCLOCKED_EINT)
dev_err(codec->dev, "Mixer underclocked\n");
dev_err(wm5100->dev, "Mixer underclocked\n");
}

static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol,
int event)
{
struct snd_soc_codec *codec = w->codec;
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int ret;

ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_3);
ret &= WM5100_SPK_SHUTDOWN_WARN_STS |
WM5100_SPK_SHUTDOWN_STS | WM5100_CLKGEN_ERR_STS |
WM5100_CLKGEN_ERR_ASYNC_STS;
wm5100_log_status3(codec, ret);
wm5100_log_status3(wm5100, ret);

ret = snd_soc_read(codec, WM5100_INTERRUPT_RAW_STATUS_4);
wm5100_log_status4(codec, ret);
wm5100_log_status4(wm5100, ret);

return 0;
}
Expand Down Expand Up @@ -2123,55 +2125,59 @@ static int wm5100_dig_vu[] = {
WM5100_DAC_DIGITAL_VOLUME_6R,
};

static void wm5100_set_detect_mode(struct snd_soc_codec *codec, int the_mode)
static void wm5100_set_detect_mode(struct wm5100_priv *wm5100, int the_mode)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
struct wm5100_jack_mode *mode = &wm5100->pdata.jack_modes[the_mode];

BUG_ON(the_mode >= ARRAY_SIZE(wm5100->pdata.jack_modes));

gpio_set_value_cansleep(wm5100->pdata.hp_pol, mode->hp_pol);
snd_soc_update_bits(codec, WM5100_ACCESSORY_DETECT_MODE_1,
WM5100_ACCDET_BIAS_SRC_MASK |
WM5100_ACCDET_SRC,
(mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) |
mode->micd_src << WM5100_ACCDET_SRC_SHIFT);
snd_soc_update_bits(codec, WM5100_MISC_CONTROL,
WM5100_HPCOM_SRC,
mode->micd_src << WM5100_HPCOM_SRC_SHIFT);
regmap_update_bits(wm5100->regmap, WM5100_ACCESSORY_DETECT_MODE_1,
WM5100_ACCDET_BIAS_SRC_MASK |
WM5100_ACCDET_SRC,
(mode->bias << WM5100_ACCDET_BIAS_SRC_SHIFT) |
mode->micd_src << WM5100_ACCDET_SRC_SHIFT);
regmap_update_bits(wm5100->regmap, WM5100_MISC_CONTROL,
WM5100_HPCOM_SRC,
mode->micd_src << WM5100_HPCOM_SRC_SHIFT);

wm5100->jack_mode = the_mode;

dev_dbg(codec->dev, "Set microphone polarity to %d\n",
dev_dbg(wm5100->dev, "Set microphone polarity to %d\n",
wm5100->jack_mode);
}

static void wm5100_micd_irq(struct snd_soc_codec *codec)
static void wm5100_micd_irq(struct wm5100_priv *wm5100)
{
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
int val;
unsigned int val;
int ret;

val = snd_soc_read(codec, WM5100_MIC_DETECT_3);
ret = regmap_read(wm5100->regmap, WM5100_MIC_DETECT_3, &val);
if (ret != 0) {
dev_err(wm5100->dev, "Failed to read micropone status: %d\n",
ret);
return;
}

dev_dbg(codec->dev, "Microphone event: %x\n", val);
dev_dbg(wm5100->dev, "Microphone event: %x\n", val);

if (!(val & WM5100_ACCDET_VALID)) {
dev_warn(codec->dev, "Microphone detection state invalid\n");
dev_warn(wm5100->dev, "Microphone detection state invalid\n");
return;
}

/* No accessory, reset everything and report removal */
if (!(val & WM5100_ACCDET_STS)) {
dev_dbg(codec->dev, "Jack removal detected\n");
dev_dbg(wm5100->dev, "Jack removal detected\n");
wm5100->jack_mic = false;
wm5100->jack_detecting = true;
snd_soc_jack_report(wm5100->jack, 0,
SND_JACK_LINEOUT | SND_JACK_HEADSET |
SND_JACK_BTN_0);

snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
WM5100_ACCDET_RATE_MASK,
WM5100_ACCDET_RATE_MASK);
regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
WM5100_ACCDET_RATE_MASK,
WM5100_ACCDET_RATE_MASK);
return;
}

Expand All @@ -2181,19 +2187,19 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec)
*/
if (val & 0x400) {
if (wm5100->jack_detecting) {
dev_dbg(codec->dev, "Microphone detected\n");
dev_dbg(wm5100->dev, "Microphone detected\n");
wm5100->jack_mic = true;
snd_soc_jack_report(wm5100->jack,
SND_JACK_HEADSET,
SND_JACK_HEADSET | SND_JACK_BTN_0);

/* Increase poll rate to give better responsiveness
* for buttons */
snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
WM5100_ACCDET_RATE_MASK,
5 << WM5100_ACCDET_RATE_SHIFT);
regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
WM5100_ACCDET_RATE_MASK,
5 << WM5100_ACCDET_RATE_SHIFT);
} else {
dev_dbg(codec->dev, "Mic button up\n");
dev_dbg(wm5100->dev, "Mic button up\n");
snd_soc_jack_report(wm5100->jack, 0, SND_JACK_BTN_0);
}

Expand All @@ -2206,7 +2212,7 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec)
* plain headphones.
*/
if (wm5100->jack_detecting && (val & 0x3f8)) {
wm5100_set_detect_mode(codec, !wm5100->jack_mode);
wm5100_set_detect_mode(wm5100, !wm5100->jack_mode);

return;
}
Expand All @@ -2216,20 +2222,20 @@ static void wm5100_micd_irq(struct snd_soc_codec *codec)
*/
if (val & 0x3fc) {
if (wm5100->jack_mic) {
dev_dbg(codec->dev, "Mic button detected\n");
dev_dbg(wm5100->dev, "Mic button detected\n");
snd_soc_jack_report(wm5100->jack, SND_JACK_BTN_0,
SND_JACK_BTN_0);
} else if (wm5100->jack_detecting) {
dev_dbg(codec->dev, "Headphone detected\n");
dev_dbg(wm5100->dev, "Headphone detected\n");
snd_soc_jack_report(wm5100->jack, SND_JACK_HEADPHONE,
SND_JACK_HEADPHONE);

/* Increase the detection rate a bit for
* responsiveness.
*/
snd_soc_update_bits(codec, WM5100_MIC_DETECT_1,
WM5100_ACCDET_RATE_MASK,
7 << WM5100_ACCDET_RATE_SHIFT);
regmap_update_bits(wm5100->regmap, WM5100_MIC_DETECT_1,
WM5100_ACCDET_RATE_MASK,
7 << WM5100_ACCDET_RATE_SHIFT);
}
}
}
Expand All @@ -2242,7 +2248,7 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
wm5100->jack = jack;
wm5100->jack_detecting = true;

wm5100_set_detect_mode(codec, 0);
wm5100_set_detect_mode(wm5100, 0);

/* Slowest detection rate, gives debounce for initial
* detection */
Expand Down Expand Up @@ -2281,52 +2287,70 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)

static irqreturn_t wm5100_irq(int irq, void *data)
{
struct snd_soc_codec *codec = data;
struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
struct wm5100_priv *wm5100 = data;
irqreturn_t status = IRQ_NONE;
int irq_val;
unsigned int irq_val, mask_val;
int ret;

irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3);
if (irq_val < 0) {
dev_err(codec->dev, "Failed to read IRQ status 3: %d\n",
irq_val);
ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, &irq_val);
if (ret < 0) {
dev_err(wm5100->dev, "Failed to read IRQ status 3: %d\n",
ret);
irq_val = 0;
}
irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_3_MASK);

snd_soc_write(codec, WM5100_INTERRUPT_STATUS_3, irq_val);
ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_3_MASK,
&mask_val);
if (ret < 0) {
dev_err(wm5100->dev, "Failed to read IRQ mask 3: %d\n",
ret);
mask_val = 0xffff;
}

irq_val &= ~mask_val;

regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_3, irq_val);

if (irq_val)
status = IRQ_HANDLED;

wm5100_log_status3(codec, irq_val);
wm5100_log_status3(wm5100, irq_val);

if (irq_val & WM5100_FLL1_LOCK_EINT) {
dev_dbg(codec->dev, "FLL1 locked\n");
dev_dbg(wm5100->dev, "FLL1 locked\n");
complete(&wm5100->fll[0].lock);
}
if (irq_val & WM5100_FLL2_LOCK_EINT) {
dev_dbg(codec->dev, "FLL2 locked\n");
dev_dbg(wm5100->dev, "FLL2 locked\n");
complete(&wm5100->fll[1].lock);
}

if (irq_val & WM5100_ACCDET_EINT)
wm5100_micd_irq(codec);
wm5100_micd_irq(wm5100);

irq_val = snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4);
if (irq_val < 0) {
dev_err(codec->dev, "Failed to read IRQ status 4: %d\n",
irq_val);
ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, &irq_val);
if (ret < 0) {
dev_err(wm5100->dev, "Failed to read IRQ status 4: %d\n",
ret);
irq_val = 0;
}
irq_val &= ~snd_soc_read(codec, WM5100_INTERRUPT_STATUS_4_MASK);

ret = regmap_read(wm5100->regmap, WM5100_INTERRUPT_STATUS_4_MASK,
&mask_val);
if (ret < 0) {
dev_err(wm5100->dev, "Failed to read IRQ mask 4: %d\n",
ret);
mask_val = 0xffff;
}

irq_val &= ~mask_val;

if (irq_val)
status = IRQ_HANDLED;

snd_soc_write(codec, WM5100_INTERRUPT_STATUS_4, irq_val);
regmap_write(wm5100->regmap, WM5100_INTERRUPT_STATUS_4, irq_val);

wm5100_log_status4(codec, irq_val);
wm5100_log_status4(wm5100, irq_val);

return status;
}
Expand Down Expand Up @@ -2485,11 +2509,12 @@ static int wm5100_probe(struct snd_soc_codec *codec)

if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
ret = request_threaded_irq(i2c->irq, NULL,
wm5100_edge_irq,
irq_flags, "wm5100", codec);
wm5100_edge_irq, irq_flags,
"wm5100", wm5100);
else
ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq,
irq_flags, "wm5100", codec);
irq_flags, "wm5100",
wm5100);

if (ret != 0) {
dev_err(codec->dev, "Failed to request IRQ %d: %d\n",
Expand Down Expand Up @@ -2552,7 +2577,7 @@ static int wm5100_probe(struct snd_soc_codec *codec)

err_gpio:
if (i2c->irq)
free_irq(i2c->irq, codec);
free_irq(i2c->irq, wm5100);

return ret;
}
Expand All @@ -2566,7 +2591,8 @@ static int wm5100_remove(struct snd_soc_codec *codec)
gpio_free(wm5100->pdata.hp_pol);
}
if (i2c->irq)
free_irq(i2c->irq, codec);
free_irq(i2c->irq, wm5100);

return 0;
}

Expand Down Expand Up @@ -2622,6 +2648,8 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
if (wm5100 == NULL)
return -ENOMEM;

wm5100->dev = &i2c->dev;

wm5100->regmap = regmap_init_i2c(i2c, &wm5100_regmap);
if (IS_ERR(wm5100->regmap)) {
ret = PTR_ERR(wm5100->regmap);
Expand Down

0 comments on commit 7911857

Please sign in to comment.