* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
- *
- * Revision history
- * 4th Feb 2006 Initial version.
*/
#include <linux/init.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
+#include "wm9712.h"
#define WM9712_VERSION "0.4"
* WM9712 register cache
*/
static const u16 wm9712_reg[] = {
- 0x6174, 0x8000, 0x8000, 0x8000, // 6
- 0x0f0f, 0xaaa0, 0xc008, 0x6808, // e
- 0xe808, 0xaaa0, 0xad00, 0x8000, // 16
- 0xe808, 0x3000, 0x8000, 0x0000, // 1e
- 0x0000, 0x0000, 0x0000, 0x000f, // 26
- 0x0405, 0x0410, 0xbb80, 0xbb80, // 2e
- 0x0000, 0xbb80, 0x0000, 0x0000, // 36
- 0x0000, 0x2000, 0x0000, 0x0000, // 3e
- 0x0000, 0x0000, 0x0000, 0x0000, // 46
- 0x0000, 0x0000, 0xf83e, 0xffff, // 4e
- 0x0000, 0x0000, 0x0000, 0xf83e, // 56
- 0x0008, 0x0000, 0x0000, 0x0000, // 5e
- 0xb032, 0x3e00, 0x0000, 0x0000, // 66
- 0x0000, 0x0000, 0x0000, 0x0000, // 6e
- 0x0000, 0x0000, 0x0000, 0x0006, // 76
- 0x0001, 0x0000, 0x574d, 0x4c12, // 7e
- 0x0000, 0x0000 // virtual hp mixers
+ 0x6174, 0x8000, 0x8000, 0x8000, /* 6 */
+ 0x0f0f, 0xaaa0, 0xc008, 0x6808, /* e */
+ 0xe808, 0xaaa0, 0xad00, 0x8000, /* 16 */
+ 0xe808, 0x3000, 0x8000, 0x0000, /* 1e */
+ 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */
+ 0x0405, 0x0410, 0xbb80, 0xbb80, /* 2e */
+ 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */
+ 0x0000, 0x2000, 0x0000, 0x0000, /* 3e */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 46 */
+ 0x0000, 0x0000, 0xf83e, 0xffff, /* 4e */
+ 0x0000, 0x0000, 0x0000, 0xf83e, /* 56 */
+ 0x0008, 0x0000, 0x0000, 0x0000, /* 5e */
+ 0xb032, 0x3e00, 0x0000, 0x0000, /* 66 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */
+ 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */
+ 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */
+ 0x0000, 0x0000 /* virtual hp mixers */
};
/* virtual HP mixers regs */
SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1),
SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
-SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE,15, 1, 1),
+SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) {
err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm9712_snd_ac97_controls[i],codec, NULL));
+ snd_soc_cnew(&wm9712_snd_ac97_controls[i],
+ codec, NULL));
if (err < 0)
return err;
}
SND_SOC_DAPM_INPUT("MIC2"),
};
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
/* virtual mixer - mixes left & right channels for spk and mono */
{"AC97 Mixer", NULL, "Left DAC"},
{"AC97 Mixer", NULL, "Right DAC"},
{"Left HP Mixer", "PCM Playback Switch", "Left DAC"},
{"Left HP Mixer", "Mic Sidetone Switch", "Mic PGA"},
{"Left HP Mixer", NULL, "ALC Sidetone Mux"},
- //{"Right HP Mixer", NULL, "HP Mixer"},
/* Right HP mixer */
{"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
{"Speaker PGA", NULL, "Speaker Mux"},
{"LOUT2", NULL, "Speaker PGA"},
{"ROUT2", NULL, "Speaker PGA"},
-
- {NULL, NULL, NULL},
};
static int wm9712_add_widgets(struct snd_soc_codec *codec)
{
- int i;
+ snd_soc_dapm_new_controls(codec, wm9712_dapm_widgets,
+ ARRAY_SIZE(wm9712_dapm_widgets));
- for(i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) {
- snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]);
- }
-
- /* set up audio path audio_mapnects */
- for(i = 0; audio_map[i][0] != NULL; i++) {
- snd_soc_dapm_connect_input(codec, audio_map[i][0],
- audio_map[i][1], audio_map[i][2]);
- }
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_new_widgets(codec);
return 0;
}
#define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000)
-struct snd_soc_codec_dai wm9712_dai[] = {
+struct snd_soc_dai wm9712_dai[] = {
{
.name = "AC97 HiFi",
.type = SND_SOC_DAI_AC97_BUS,
};
EXPORT_SYMBOL_GPL(wm9712_dai);
-static int wm9712_dapm_event(struct snd_soc_codec *codec, int event)
+static int wm9712_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
{
- u16 reg;
-
- switch (event) {
- case SNDRV_CTL_POWER_D0: /* full On */
- /* liam - maybe enable thermal shutdown */
- reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xdfff;
- ac97_write(codec, AC97_EXTENDED_MID, reg);
- break;
- case SNDRV_CTL_POWER_D1: /* partial On */
- case SNDRV_CTL_POWER_D2: /* partial On */
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
break;
- case SNDRV_CTL_POWER_D3hot: /* Off, with power */
- /* enable master bias and vmid */
- reg = ac97_read(codec, AC97_EXTENDED_MID) & 0xbbff;
- ac97_write(codec, AC97_EXTENDED_MID, reg);
+ case SND_SOC_BIAS_STANDBY:
ac97_write(codec, AC97_POWERDOWN, 0x0000);
break;
- case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+ case SND_SOC_BIAS_OFF:
/* disable everything including AC link */
- ac97_write(codec, AC97_EXTENDED_MID, 0xffff);
ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff);
ac97_write(codec, AC97_POWERDOWN, 0xffff);
break;
}
- codec->dapm_state = event;
+ codec->bias_level = level;
return 0;
}
{
if (try_warm && soc_ac97_ops.warm_reset) {
soc_ac97_ops.warm_reset(codec->ac97);
- if (!(ac97_read(codec, 0) & 0x8000))
+ if (ac97_read(codec, 0) == wm9712_reg[0])
return 1;
}
soc_ac97_ops.reset(codec->ac97);
- if (ac97_read(codec, 0) & 0x8000)
+ if (ac97_read(codec, 0) != wm9712_reg[0])
goto err;
return 0;
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->codec;
- wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+ wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
u16 *cache = codec->reg_cache;
ret = wm9712_reset(codec, 1);
- if (ret < 0){
+ if (ret < 0) {
printk(KERN_ERR "could not reset AC97 codec\n");
return ret;
}
- wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
if (ret == 0) {
/* Sync reg_cache with the hardware after cold reset */
- for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i+=2) {
+ for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i += 2) {
if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||
- (i > 0x58 && i != 0x5c))
+ (i > 0x58 && i != 0x5c))
continue;
soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
}
}
- if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0)
- wm9712_dapm_event(codec, SNDRV_CTL_POWER_D0);
+ if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
+ wm9712_set_bias_level(codec, SND_SOC_BIAS_ON);
return ret;
}
codec->num_dai = ARRAY_SIZE(wm9712_dai);
codec->write = ac97_write;
codec->read = ac97_read;
- codec->dapm_event = wm9712_dapm_event;
+ codec->set_bias_level = wm9712_set_bias_level;
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
/* set alc mux to none */
ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
- wm9712_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
wm9712_add_controls(codec);
wm9712_add_widgets(codec);
ret = snd_soc_register_card(socdev);
.suspend = wm9712_soc_suspend,
.resume = wm9712_soc_resume,
};
-
EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);
MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");