#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
-#include <sound/driver.h>
#include <sound/core.h>
#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 <asm/div64.h>
#include "wm8753.h"
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
- wm8753_write_reg_cache (codec, reg, value);
+ wm8753_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
static const char *wm8753_dai_mode[] = {"DAI 0", "DAI 1", "DAI 2", "DAI 3"};
static const char *wm8753_dat_sel[] = {"Stereo", "Left ADC", "Right ADC",
"Channel Swap"};
+static const char *wm8753_rout2_phase[] = {"Non Inverted", "Inverted"};
static const struct soc_enum wm8753_enum[] = {
SOC_ENUM_SINGLE(WM8753_BASS, 7, 2, wm8753_base),
SOC_ENUM_SINGLE(WM8753_MICBIAS, 6, 3, wm8753_mic_sel),
SOC_ENUM_SINGLE(WM8753_IOCTL, 2, 4, wm8753_dai_mode),
SOC_ENUM_SINGLE(WM8753_ADC, 7, 4, wm8753_dat_sel),
+SOC_ENUM_SINGLE(WM8753_OUTCTL, 2, 2, wm8753_rout2_phase),
};
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
- if (((mode &0xc) >> 2) == ucontrol->value.integer.value[0])
+ if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
return 0;
mode &= 0xfff3;
return 1;
}
+static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600);
+
static const struct snd_kcontrol_new wm8753_snd_controls[] = {
SOC_DOUBLE_R("PCM Volume", WM8753_LDAC, WM8753_RDAC, 0, 255, 0),
SOC_SINGLE("Mono Bypass Playback Volume", WM8753_MOUTM1, 4, 7, 1),
SOC_SINGLE("Mono Sidetone Playback Volume", WM8753_MOUTM2, 4, 7, 1),
-SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 4, 7, 1),
+SOC_SINGLE("Mono Voice Playback Volume", WM8753_MOUTM2, 0, 7, 1),
SOC_SINGLE("Mono Playback ZC Switch", WM8753_MOUTV, 7, 1, 0),
SOC_ENUM("Bass Boost", wm8753_enum[0]),
SOC_SINGLE("Treble Volume", WM8753_TREBLE, 0, 15, 1),
SOC_ENUM("Treble Cut-off", wm8753_enum[2]),
-SOC_DOUBLE("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1),
-SOC_SINGLE("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1),
+SOC_DOUBLE_TLV("Sidetone Capture Volume", WM8753_RECMIX1, 0, 4, 7, 1, rec_mix_tlv),
+SOC_SINGLE_TLV("Voice Sidetone Capture Volume", WM8753_RECMIX2, 0, 7, 1, rec_mix_tlv),
SOC_DOUBLE_R("Capture Volume", WM8753_LINVOL, WM8753_RINVOL, 0, 63, 0),
SOC_DOUBLE_R("Capture ZC Switch", WM8753_LINVOL, WM8753_RINVOL, 6, 1, 0),
SOC_ENUM_EXT("DAI Mode", wm8753_enum[26], wm8753_get_dai, wm8753_set_dai),
SOC_ENUM("ADC Data Select", wm8753_enum[27]),
+SOC_ENUM("ROUT2 Phase", wm8753_enum[28]),
};
/* add non dapm controls */
for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) {
err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8753_snd_controls[i],codec, NULL));
+ snd_soc_cnew(&wm8753_snd_controls[i],
+ codec, NULL));
if (err < 0)
return err;
}
SND_SOC_DAPM_VMID("VREF"),
};
-static const char *audio_map[][3] = {
+static const struct snd_soc_dapm_route audio_map[] = {
/* left mixer */
{"Left Mixer", "Left Playback Switch", "Left DAC"},
{"Left Mixer", "Voice Playback Switch", "Voice DAC"},
/* ACOP */
{"ACOP", NULL, "ALC Mixer"},
-
- /* terminator */
- {NULL, NULL, NULL},
};
static int wm8753_add_widgets(struct snd_soc_codec *codec)
{
- int i;
+ snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
+ ARRAY_SIZE(wm8753_dapm_widgets));
- for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++)
- snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]);
-
- /* set up the WM8753 audio map */
- 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;
if ((Ndiv < 6) || (Ndiv > 12))
printk(KERN_WARNING
- "WM8753 N value outwith recommended range! N = %d\n",Ndiv);
+ "wm8753: unsupported N = %d\n", Ndiv);
pll_div->n = Ndiv;
Nmod = target % source;
return 0;
}
-static int wm8753_dapm_event(struct snd_soc_codec *codec, int event)
+static int wm8753_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
{
u16 pwr_reg = wm8753_read_reg_cache(codec, WM8753_PWR1) & 0xfe3e;
- switch (event) {
- case SNDRV_CTL_POWER_D0: /* full On */
+ switch (level) {
+ case SND_SOC_BIAS_ON:
/* set vmid to 50k and unmute dac */
wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
break;
- case SNDRV_CTL_POWER_D1: /* partial On */
- case SNDRV_CTL_POWER_D2: /* partial On */
+ case SND_SOC_BIAS_PREPARE:
/* set vmid to 5k for quick power up */
wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x01c1);
break;
- case SNDRV_CTL_POWER_D3hot: /* Off, with power */
+ case SND_SOC_BIAS_STANDBY:
/* mute dac and set vmid to 500k, enable VREF */
wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x0141);
break;
- case SNDRV_CTL_POWER_D3cold: /* Off, without power */
+ case SND_SOC_BIAS_OFF:
wm8753_write(codec, WM8753_PWR1, 0x0001);
break;
}
- codec->dapm_state = event;
+ codec->bias_level = level;
return 0;
}
#define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
- SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
#define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
{
struct snd_soc_codec *codec =
container_of(work, struct snd_soc_codec, delayed_work.work);
- wm8753_dapm_event(codec, codec->dapm_state);
+ wm8753_set_bias_level(codec, codec->bias_level);
}
static int wm8753_suspend(struct platform_device *pdev, pm_message_t state)
struct snd_soc_codec *codec = socdev->codec;
/* we only need to suspend if we are a valid card */
- if(!codec->card)
+ if (!codec->card)
return 0;
-
- wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
u16 *cache = codec->reg_cache;
/* we only need to resume if we are a valid card */
- if(!codec->card)
+ if (!codec->card)
return 0;
/* Sync reg_cache with the hardware */
codec->hw_write(codec->control_data, data, 2);
}
- wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* charge wm8753 caps */
- if (codec->suspend_dapm_state == SNDRV_CTL_POWER_D0) {
- wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2);
- codec->dapm_state = SNDRV_CTL_POWER_D0;
+ if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+ codec->bias_level = SND_SOC_BIAS_ON;
schedule_delayed_work(&codec->delayed_work,
msecs_to_jiffies(caps_charge));
}
codec->owner = THIS_MODULE;
codec->read = wm8753_read_reg_cache;
codec->write = wm8753_write;
- codec->dapm_event = wm8753_dapm_event;
+ codec->set_bias_level = wm8753_set_bias_level;
codec->dai = wm8753_dai;
codec->num_dai = 2;
- codec->reg_cache_size = sizeof(wm8753_reg);
+ codec->reg_cache_size = ARRAY_SIZE(wm8753_reg);
codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL);
if (codec->reg_cache == NULL)
}
/* charge output caps */
- wm8753_dapm_event(codec, SNDRV_CTL_POWER_D2);
- codec->dapm_state = SNDRV_CTL_POWER_D3hot;
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
+ codec->bias_level = SND_SOC_BIAS_STANDBY;
schedule_delayed_work(&codec->delayed_work,
msecs_to_jiffies(caps_charge));
wm8753_add_widgets(codec);
ret = snd_soc_register_card(socdev);
if (ret < 0) {
- printk(KERN_ERR "wm8753: failed to register card\n");
+ printk(KERN_ERR "wm8753: failed to register card\n");
goto card_err;
- }
+ }
+
return ret;
card_err:
around */
static struct snd_soc_device *wm8753_socdev;
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/*
* WM8753 2 wire address is determined by GPIO5
client_template.addr = addr;
i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
- if (i2c == NULL){
+ if (!i2c) {
kfree(codec);
return -ENOMEM;
}
wm8753_socdev = socdev;
INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
if (setup->i2c_address) {
normal_i2c[0] = setup->i2c_address;
codec->hw_write = (hw_write_t)i2c_master_send;
struct snd_soc_codec *codec = socdev->codec;
if (codec->control_data)
- wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
+ wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
run_delayed_work(&codec->delayed_work);
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8753_i2c_driver);
#endif
kfree(codec->private_data);
.suspend = wm8753_suspend,
.resume = wm8753_resume,
};
-
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
MODULE_DESCRIPTION("ASoC WM8753 driver");