Merge branch 'for-2.6.32' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6 into topic/asoc

This commit is contained in:
Takashi Iwai 2009-06-25 15:28:39 +02:00
commit 62b1653e29
31 changed files with 3459 additions and 366 deletions

View file

@ -279,6 +279,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
/* dapm events */
int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
int event);
void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
/* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev);

View file

@ -192,6 +192,11 @@ void snd_soc_unregister_platform(struct snd_soc_platform *platform);
int snd_soc_register_codec(struct snd_soc_codec *codec);
void snd_soc_unregister_codec(struct snd_soc_codec *codec);
#ifdef CONFIG_PM
int snd_soc_suspend_device(struct device *dev);
int snd_soc_resume_device(struct device *dev);
#endif
/* pcm <-> DAI connect */
void snd_soc_free_pcms(struct snd_soc_device *socdev);
int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
@ -216,9 +221,9 @@ void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count,
/* codec register bit access */
int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
unsigned short mask, unsigned short value);
unsigned int mask, unsigned int value);
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
unsigned short mask, unsigned short value);
unsigned int mask, unsigned int value);
int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
struct snd_ac97_bus_ops *ops, int num);
@ -369,8 +374,6 @@ struct snd_soc_codec {
enum snd_soc_bias_level bias_level;
enum snd_soc_bias_level suspend_bias_level;
struct delayed_work delayed_work;
struct list_head up_list;
struct list_head down_list;
/* codec DAI's */
struct snd_soc_dai *dai;

22
include/sound/uda1380.h Normal file
View file

@ -0,0 +1,22 @@
/*
* UDA1380 ALSA SoC Codec driver
*
* Copyright 2009 Philipp Zabel
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __UDA1380_H
#define __UDA1380_H
struct uda1380_platform_data {
int gpio_power;
int gpio_reset;
int dac_clk;
#define UDA1380_DAC_CLK_SYSCLK 0
#define UDA1380_DAC_CLK_WSPLL 1
};
#endif /* __UDA1380_H */

View file

@ -203,23 +203,23 @@ static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
.codec_dev = &soc_codec_dev_ad73311,
};
static struct platform_device *bf52x_ad73311_snd_device;
static struct platform_device *bf5xx_ad73311_snd_device;
static int __init bf5xx_ad73311_init(void)
{
int ret;
pr_debug("%s enter\n", __func__);
bf52x_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
if (!bf52x_ad73311_snd_device)
bf5xx_ad73311_snd_device = platform_device_alloc("soc-audio", -1);
if (!bf5xx_ad73311_snd_device)
return -ENOMEM;
platform_set_drvdata(bf52x_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
bf5xx_ad73311_snd_devdata.dev = &bf52x_ad73311_snd_device->dev;
ret = platform_device_add(bf52x_ad73311_snd_device);
platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev;
ret = platform_device_add(bf5xx_ad73311_snd_device);
if (ret)
platform_device_put(bf52x_ad73311_snd_device);
platform_device_put(bf5xx_ad73311_snd_device);
return ret;
}
@ -227,7 +227,7 @@ static int __init bf5xx_ad73311_init(void)
static void __exit bf5xx_ad73311_exit(void)
{
pr_debug("%s enter\n", __func__);
platform_device_unregister(bf52x_ad73311_snd_device);
platform_device_unregister(bf5xx_ad73311_snd_device);
}
module_init(bf5xx_ad73311_init);

View file

@ -148,24 +148,24 @@ static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
.codec_data = &bf5xx_ssm2602_setup,
};
static struct platform_device *bf52x_ssm2602_snd_device;
static struct platform_device *bf5xx_ssm2602_snd_device;
static int __init bf5xx_ssm2602_init(void)
{
int ret;
pr_debug("%s enter\n", __func__);
bf52x_ssm2602_snd_device = platform_device_alloc("soc-audio", -1);
if (!bf52x_ssm2602_snd_device)
bf5xx_ssm2602_snd_device = platform_device_alloc("soc-audio", -1);
if (!bf5xx_ssm2602_snd_device)
return -ENOMEM;
platform_set_drvdata(bf52x_ssm2602_snd_device,
platform_set_drvdata(bf5xx_ssm2602_snd_device,
&bf5xx_ssm2602_snd_devdata);
bf5xx_ssm2602_snd_devdata.dev = &bf52x_ssm2602_snd_device->dev;
ret = platform_device_add(bf52x_ssm2602_snd_device);
bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev;
ret = platform_device_add(bf5xx_ssm2602_snd_device);
if (ret)
platform_device_put(bf52x_ssm2602_snd_device);
platform_device_put(bf5xx_ssm2602_snd_device);
return ret;
}
@ -173,7 +173,7 @@ static int __init bf5xx_ssm2602_init(void)
static void __exit bf5xx_ssm2602_exit(void)
{
pr_debug("%s enter\n", __func__);
platform_device_unregister(bf52x_ssm2602_snd_device);
platform_device_unregister(bf5xx_ssm2602_snd_device);
}
module_init(bf5xx_ssm2602_init);

View file

@ -39,6 +39,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8903 if I2C
select SND_SOC_WM8940 if I2C
select SND_SOC_WM8960 if I2C
select SND_SOC_WM8961 if I2C
select SND_SOC_WM8971 if I2C
select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8990 if I2C
@ -156,6 +157,9 @@ config SND_SOC_WM8940
config SND_SOC_WM8960
tristate
config SND_SOC_WM8961
tristate
config SND_SOC_WM8971
tristate

View file

@ -27,6 +27,7 @@ snd-soc-wm8900-objs := wm8900.o
snd-soc-wm8903-objs := wm8903.o
snd-soc-wm8940-objs := wm8940.o
snd-soc-wm8960-objs := wm8960.o
snd-soc-wm8961-objs := wm8961.o
snd-soc-wm8971-objs := wm8971.o
snd-soc-wm8988-objs := wm8988.o
snd-soc-wm8990-objs := wm8990.o
@ -65,6 +66,7 @@ obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o
obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o
obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o
obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o
obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o
obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o

View file

@ -712,7 +712,19 @@ static int bypass_event(struct snd_soc_dapm_widget *w,
reg = twl4030_read_reg_cache(w->codec, m->reg);
if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
/*
* bypass_state[0:3] - analog HiFi bypass
* bypass_state[4] - analog voice bypass
* bypass_state[5] - digital voice bypass
* bypass_state[6:7] - digital HiFi bypass
*/
if (m->reg == TWL4030_REG_VSTPGA) {
/* Voice digital bypass */
if (reg)
twl4030->bypass_state |= (1 << 5);
else
twl4030->bypass_state &= ~(1 << 5);
} else if (m->reg <= TWL4030_REG_ARXR2_APGA_CTL) {
/* Analog bypass */
if (reg & (1 << m->shift))
twl4030->bypass_state |=
@ -726,12 +738,6 @@ static int bypass_event(struct snd_soc_dapm_widget *w,
twl4030->bypass_state |= (1 << 4);
else
twl4030->bypass_state &= ~(1 << 4);
} else if (m->reg == TWL4030_REG_VSTPGA) {
/* Voice digital bypass */
if (reg)
twl4030->bypass_state |= (1 << 5);
else
twl4030->bypass_state &= ~(1 << 5);
} else {
/* Digital bypass */
if (reg & (0x7 << m->shift))
@ -924,7 +930,7 @@ static const struct soc_enum twl4030_op_modes_enum =
ARRAY_SIZE(twl4030_op_modes_texts),
twl4030_op_modes_texts);
int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
@ -1005,6 +1011,16 @@ static DECLARE_TLV_DB_SCALE(digital_capture_tlv, 0, 100, 0);
*/
static DECLARE_TLV_DB_SCALE(input_gain_tlv, 0, 600, 0);
/* AVADC clock priority */
static const char *twl4030_avadc_clk_priority_texts[] = {
"Voice high priority", "HiFi high priority"
};
static const struct soc_enum twl4030_avadc_clk_priority_enum =
SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2,
ARRAY_SIZE(twl4030_avadc_clk_priority_texts),
twl4030_avadc_clk_priority_texts);
static const char *twl4030_rampdelay_texts[] = {
"27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms",
"437/323/218 ms", "874/645/437 ms", "1748/1291/874 ms",
@ -1106,6 +1122,8 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
SOC_DOUBLE_TLV("Analog Capture Volume", TWL4030_REG_ANAMIC_GAIN,
0, 3, 5, 0, input_gain_tlv),
SOC_ENUM("AVADC Clock Priority", twl4030_avadc_clk_priority_enum),
SOC_ENUM("HS ramp delay", twl4030_rampdelay_enum),
SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum),
@ -1609,8 +1627,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
/* If the substream has 4 channel, do the necessary setup */
if (params_channels(params) == 4) {
u8 format, mode;
format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE);
@ -1948,7 +1964,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFM:
case SND_SOC_DAIFMT_CBM_CFM:
format &= ~(TWL4030_VIF_SLAVE_EN);
break;
case SND_SOC_DAIFMT_CBS_CFS:

View file

@ -5,9 +5,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com>
* Improved support for DAPM and audio routing/mixing capabilities,
* added TLV support.
* Copyright (c) 2007-2009 Philipp Zabel <philipp.zabel@gmail.com>
*
* Modified by Richard Purdie <richard@openedhand.com> to fit into SoC
* codec model.
@ -19,26 +17,32 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/initval.h>
#include <sound/info.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/uda1380.h>
#include "uda1380.h"
static struct work_struct uda1380_work;
static struct snd_soc_codec *uda1380_codec;
/* codec private data */
struct uda1380_priv {
struct snd_soc_codec codec;
u16 reg_cache[UDA1380_CACHEREGNUM];
unsigned int dac_clk;
struct work_struct work;
};
/*
* uda1380 register cache
*/
@ -473,6 +477,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct uda1380_priv *uda1380 = codec->private_data;
int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
switch (cmd) {
@ -480,13 +485,13 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
uda1380_write_reg_cache(codec, UDA1380_MIXER,
mixer & ~R14_SILENCE);
schedule_work(&uda1380_work);
schedule_work(&uda1380->work);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
uda1380_write_reg_cache(codec, UDA1380_MIXER,
mixer | R14_SILENCE);
schedule_work(&uda1380_work);
schedule_work(&uda1380->work);
break;
}
return 0;
@ -670,44 +675,33 @@ static int uda1380_resume(struct platform_device *pdev)
return 0;
}
/*
* initialise the UDA1380 driver
* register mixer and dsp interfaces with the kernel
*/
static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
static int uda1380_probe(struct platform_device *pdev)
{
struct snd_soc_codec *codec = socdev->card->codec;
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
struct uda1380_platform_data *pdata;
int ret = 0;
codec->name = "UDA1380";
codec->owner = THIS_MODULE;
codec->read = uda1380_read_reg_cache;
codec->write = uda1380_write;
codec->set_bias_level = uda1380_set_bias_level;
codec->dai = uda1380_dai;
codec->num_dai = ARRAY_SIZE(uda1380_dai);
codec->reg_cache = kmemdup(uda1380_reg, sizeof(uda1380_reg),
GFP_KERNEL);
if (codec->reg_cache == NULL)
return -ENOMEM;
codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
codec->reg_cache_step = 1;
uda1380_reset(codec);
if (uda1380_codec == NULL) {
dev_err(&pdev->dev, "Codec device not registered\n");
return -ENODEV;
}
uda1380_codec = codec;
INIT_WORK(&uda1380_work, uda1380_flush_work);
socdev->card->codec = uda1380_codec;
codec = uda1380_codec;
pdata = codec->dev->platform_data;
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
pr_err("uda1380: failed to create pcms\n");
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
goto pcm_err;
}
/* power on device */
uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* set clock input */
switch (dac_clk) {
switch (pdata->dac_clk) {
case UDA1380_DAC_CLK_SYSCLK:
uda1380_write(codec, UDA1380_CLK, 0);
break;
@ -716,13 +710,12 @@ static int uda1380_init(struct snd_soc_device *socdev, int dac_clk)
break;
}
/* uda1380 init */
snd_soc_add_controls(codec, uda1380_snd_controls,
ARRAY_SIZE(uda1380_snd_controls));
uda1380_add_widgets(codec);
ret = snd_soc_init_card(socdev);
if (ret < 0) {
pr_err("uda1380: failed to register card\n");
dev_err(codec->dev, "failed to register card: %d\n", ret);
goto card_err;
}
@ -732,36 +725,164 @@ card_err:
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
pcm_err:
kfree(codec->reg_cache);
return ret;
}
static struct snd_soc_device *uda1380_socdev;
/* power down chip */
static int uda1380_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
return 0;
}
struct snd_soc_codec_device soc_codec_dev_uda1380 = {
.probe = uda1380_probe,
.remove = uda1380_remove,
.suspend = uda1380_suspend,
.resume = uda1380_resume,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
static int uda1380_register(struct uda1380_priv *uda1380)
{
int ret, i;
struct snd_soc_codec *codec = &uda1380->codec;
struct uda1380_platform_data *pdata = codec->dev->platform_data;
if (uda1380_codec) {
dev_err(codec->dev, "Another UDA1380 is registered\n");
return -EINVAL;
}
if (!pdata || !pdata->gpio_power || !pdata->gpio_reset)
return -EINVAL;
ret = gpio_request(pdata->gpio_power, "uda1380 power");
if (ret)
goto err_out;
ret = gpio_request(pdata->gpio_reset, "uda1380 reset");
if (ret)
goto err_gpio;
gpio_direction_output(pdata->gpio_power, 1);
/* we may need to have the clock running here - pH5 */
gpio_direction_output(pdata->gpio_reset, 1);
udelay(5);
gpio_set_value(pdata->gpio_reset, 0);
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
codec->private_data = uda1380;
codec->name = "UDA1380";
codec->owner = THIS_MODULE;
codec->read = uda1380_read_reg_cache;
codec->write = uda1380_write;
codec->bias_level = SND_SOC_BIAS_OFF;
codec->set_bias_level = uda1380_set_bias_level;
codec->dai = uda1380_dai;
codec->num_dai = ARRAY_SIZE(uda1380_dai);
codec->reg_cache_size = ARRAY_SIZE(uda1380_reg);
codec->reg_cache = &uda1380->reg_cache;
codec->reg_cache_step = 1;
memcpy(codec->reg_cache, uda1380_reg, sizeof(uda1380_reg));
ret = uda1380_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
goto err_reset;
}
INIT_WORK(&uda1380->work, uda1380_flush_work);
for (i = 0; i < ARRAY_SIZE(uda1380_dai); i++)
uda1380_dai[i].dev = codec->dev;
uda1380_codec = codec;
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
goto err_reset;
}
ret = snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
goto err_dai;
}
return 0;
err_dai:
snd_soc_unregister_codec(codec);
err_reset:
gpio_set_value(pdata->gpio_power, 0);
gpio_free(pdata->gpio_reset);
err_gpio:
gpio_free(pdata->gpio_power);
err_out:
return ret;
}
static void uda1380_unregister(struct uda1380_priv *uda1380)
{
struct snd_soc_codec *codec = &uda1380->codec;
struct uda1380_platform_data *pdata = codec->dev->platform_data;
snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
snd_soc_unregister_codec(&uda1380->codec);
gpio_set_value(pdata->gpio_power, 0);
gpio_free(pdata->gpio_reset);
gpio_free(pdata->gpio_power);
kfree(uda1380);
uda1380_codec = NULL;
}
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int uda1380_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
static __devinit int uda1380_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct snd_soc_device *socdev = uda1380_socdev;
struct uda1380_setup_data *setup = socdev->codec_data;
struct snd_soc_codec *codec = socdev->card->codec;
struct uda1380_priv *uda1380;
struct snd_soc_codec *codec;
int ret;
i2c_set_clientdata(i2c, codec);
uda1380 = kzalloc(sizeof(struct uda1380_priv), GFP_KERNEL);
if (uda1380 == NULL)
return -ENOMEM;
codec = &uda1380->codec;
codec->hw_write = (hw_write_t)i2c_master_send;
i2c_set_clientdata(i2c, uda1380);
codec->control_data = i2c;
ret = uda1380_init(socdev, setup->dac_clk);
if (ret < 0)
pr_err("uda1380: failed to initialise UDA1380\n");
codec->dev = &i2c->dev;
ret = uda1380_register(uda1380);
if (ret != 0)
kfree(uda1380);
return ret;
}
static int uda1380_i2c_remove(struct i2c_client *client)
static int __devexit uda1380_i2c_remove(struct i2c_client *i2c)
{
struct snd_soc_codec *codec = i2c_get_clientdata(client);
kfree(codec->reg_cache);
struct uda1380_priv *uda1380 = i2c_get_clientdata(i2c);
uda1380_unregister(uda1380);
return 0;
}
@ -777,120 +898,28 @@ static struct i2c_driver uda1380_i2c_driver = {
.owner = THIS_MODULE,
},
.probe = uda1380_i2c_probe,
.remove = uda1380_i2c_remove,
.remove = __devexit_p(uda1380_i2c_remove),
.id_table = uda1380_i2c_id,
};
static int uda1380_add_i2c_device(struct platform_device *pdev,
const struct uda1380_setup_data *setup)
{
struct i2c_board_info info;
struct i2c_adapter *adapter;
struct i2c_client *client;
int ret;
ret = i2c_add_driver(&uda1380_i2c_driver);
if (ret != 0) {
dev_err(&pdev->dev, "can't add i2c driver\n");
return ret;
}
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = setup->i2c_address;
strlcpy(info.type, "uda1380", I2C_NAME_SIZE);
adapter = i2c_get_adapter(setup->i2c_bus);
if (!adapter) {
dev_err(&pdev->dev, "can't get i2c adapter %d\n",
setup->i2c_bus);
goto err_driver;
}
client = i2c_new_device(adapter, &info);
i2c_put_adapter(adapter);
if (!client) {
dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
(unsigned int)info.addr);
goto err_driver;
}
return 0;
err_driver:
i2c_del_driver(&uda1380_i2c_driver);
return -ENODEV;
}
#endif
static int uda1380_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct uda1380_setup_data *setup;
struct snd_soc_codec *codec;
int ret;
setup = socdev->codec_data;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
return -ENOMEM;
socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
uda1380_socdev = socdev;
ret = -ENODEV;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
if (setup->i2c_address) {
codec->hw_write = (hw_write_t)i2c_master_send;
ret = uda1380_add_i2c_device(pdev, setup);
}
#endif
if (ret != 0)
kfree(codec);
return ret;
}
/* power down chip */
static int uda1380_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
if (codec->control_data)
uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_unregister_device(codec->control_data);
i2c_del_driver(&uda1380_i2c_driver);
#endif
kfree(codec);
return 0;
}
struct snd_soc_codec_device soc_codec_dev_uda1380 = {
.probe = uda1380_probe,
.remove = uda1380_remove,
.suspend = uda1380_suspend,
.resume = uda1380_resume,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_uda1380);
static int __init uda1380_modinit(void)
{
return snd_soc_register_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
int ret;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&uda1380_i2c_driver);
if (ret != 0)
pr_err("Failed to register UDA1380 I2C driver: %d\n", ret);
#endif
return 0;
}
module_init(uda1380_modinit);
static void __exit uda1380_exit(void)
{
snd_soc_unregister_dais(uda1380_dai, ARRAY_SIZE(uda1380_dai));
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&uda1380_i2c_driver);
#endif
}
module_exit(uda1380_exit);

View file

@ -72,14 +72,6 @@
#define R22_SKIP_DCFIL 0x0002
#define R23_AGC_EN 0x0001
struct uda1380_setup_data {
int i2c_bus;
unsigned short i2c_address;
int dac_clk;
#define UDA1380_DAC_CLK_SYSCLK 0
#define UDA1380_DAC_CLK_WSPLL 1
};
#define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */
#define UDA1380_DAI_PLAYBACK 1 /* playback DAI */
#define UDA1380_DAI_CAPTURE 2 /* capture DAI */

View file

@ -406,7 +406,6 @@ static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" };
static const char *wm8350_dacmutem[] = { "Normal", "Soft" };
static const char *wm8350_dacmutes[] = { "Fast", "Slow" };
static const char *wm8350_dacfilter[] = { "Normal", "Sloping" };
static const char *wm8350_adcfilter[] = { "None", "High Pass" };
static const char *wm8350_adchp[] = { "44.1kHz", "8kHz", "16kHz", "32kHz" };
static const char *wm8350_lr[] = { "Left", "Right" };
@ -416,7 +415,6 @@ static const struct soc_enum wm8350_enum[] = {
SOC_ENUM_SINGLE(WM8350_DAC_CONTROL, 0, 4, wm8350_pol),
SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 14, 2, wm8350_dacmutem),
SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 13, 2, wm8350_dacmutes),
SOC_ENUM_SINGLE(WM8350_DAC_MUTE_VOLUME, 12, 2, wm8350_dacfilter),
SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 15, 2, wm8350_adcfilter),
SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 8, 4, wm8350_adchp),
SOC_ENUM_SINGLE(WM8350_ADC_CONTROL, 0, 4, wm8350_pol),
@ -444,10 +442,9 @@ static const struct snd_kcontrol_new wm8350_snd_controls[] = {
0, 255, 0, dac_pcm_tlv),
SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]),
SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]),
SOC_ENUM("Playback PCM Filter", wm8350_enum[4]),
SOC_ENUM("Capture PCM Filter", wm8350_enum[5]),
SOC_ENUM("Capture PCM HP Filter", wm8350_enum[6]),
SOC_ENUM("Capture ADC Inversion", wm8350_enum[7]),
SOC_ENUM("Capture PCM Filter", wm8350_enum[4]),
SOC_ENUM("Capture PCM HP Filter", wm8350_enum[5]),
SOC_ENUM("Capture ADC Inversion", wm8350_enum[6]),
SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume",
WM8350_ADC_DIGITAL_VOLUME_L,
WM8350_ADC_DIGITAL_VOLUME_R,
@ -993,6 +990,7 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8350 *wm8350 = codec->control_data;
u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
~WM8350_AIF_WL_MASK;
@ -1012,6 +1010,19 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
}
wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
/* The sloping stopband filter is recommended for use with
* lower sample rates to improve performance.
*/
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (params_rate(params) < 24000)
wm8350_set_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
WM8350_DAC_SB_FILT);
else
wm8350_clear_bits(wm8350, WM8350_DAC_MUTE_VOLUME,
WM8350_DAC_SB_FILT);
}
return 0;
}
@ -1660,6 +1671,21 @@ static int __devexit wm8350_codec_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int wm8350_codec_suspend(struct platform_device *pdev, pm_message_t m)
{
return snd_soc_suspend_device(&pdev->dev);
}
static int wm8350_codec_resume(struct platform_device *pdev)
{
return snd_soc_resume_device(&pdev->dev);
}
#else
#define wm8350_codec_suspend NULL
#define wm8350_codec_resume NULL
#endif
static struct platform_driver wm8350_codec_driver = {
.driver = {
.name = "wm8350-codec",
@ -1667,6 +1693,8 @@ static struct platform_driver wm8350_codec_driver = {
},
.probe = wm8350_codec_probe,
.remove = __devexit_p(wm8350_codec_remove),
.suspend = wm8350_codec_suspend,
.resume = wm8350_codec_resume,
};
static __init int wm8350_init(void)

View file

@ -1553,6 +1553,21 @@ static int __exit wm8400_codec_remove(struct platform_device *dev)
return 0;
}
#ifdef CONFIG_PM
static int wm8400_pdev_suspend(struct platform_device *pdev, pm_message_t msg)
{
return snd_soc_suspend_device(&pdev->dev);
}
static int wm8400_pdev_resume(struct platform_device *pdev)
{
return snd_soc_resume_device(&pdev->dev);
}
#else
#define wm8400_pdev_suspend NULL
#define wm8400_pdev_resume NULL
#endif
static struct platform_driver wm8400_codec_driver = {
.driver = {
.name = "wm8400-codec",
@ -1560,6 +1575,8 @@ static struct platform_driver wm8400_codec_driver = {
},
.probe = wm8400_codec_probe,
.remove = __exit_p(wm8400_codec_remove),
.suspend = wm8400_pdev_suspend,
.resume = wm8400_pdev_resume,
};
static int __init wm8400_codec_init(void)

View file

@ -24,6 +24,8 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@ -187,15 +189,22 @@ struct pll_state {
unsigned int out;
};
#define WM8580_NUM_SUPPLIES 3
static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
"AVDD",
"DVDD",
"PVDD",
};
/* codec private data */
struct wm8580_priv {
struct snd_soc_codec codec;
struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
u16 reg_cache[WM8580_MAX_REGISTER + 1];
struct pll_state a;
struct pll_state b;
};
/*
* read wm8580 register cache
*/
@ -922,11 +931,28 @@ static int wm8580_register(struct wm8580_priv *wm8580)
memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg));
for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++)
wm8580->supplies[i].supply = wm8580_supply_names[i];
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8580->supplies),
wm8580->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
goto err;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies),
wm8580->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
goto err_regulator_get;
}
/* Get the codec into a known state */
ret = wm8580_write(codec, WM8580_RESET, 0);
if (ret != 0) {
dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
goto err;
goto err_regulator_enable;
}
for (i = 0; i < ARRAY_SIZE(wm8580_dai); i++)
@ -939,7 +965,7 @@ static int wm8580_register(struct wm8580_priv *wm8580)
ret = snd_soc_register_codec(codec);
if (ret != 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
goto err;
goto err_regulator_enable;
}
ret = snd_soc_register_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
@ -952,6 +978,10 @@ static int wm8580_register(struct wm8580_priv *wm8580)
err_codec:
snd_soc_unregister_codec(codec);
err_regulator_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
err_regulator_get:
regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
err:
kfree(wm8580);
return ret;
@ -962,6 +992,8 @@ static void wm8580_unregister(struct wm8580_priv *wm8580)
wm8580_set_bias_level(&wm8580->codec, SND_SOC_BIAS_OFF);
snd_soc_unregister_dais(wm8580_dai, ARRAY_SIZE(wm8580_dai));
snd_soc_unregister_codec(&wm8580->codec);
regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
regulator_bulk_free(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
kfree(wm8580);
wm8580_codec = NULL;
}
@ -995,6 +1027,21 @@ static int wm8580_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int wm8580_i2c_suspend(struct i2c_client *client, pm_message_t msg)
{
return snd_soc_suspend_device(&client->dev);
}
static int wm8580_i2c_resume(struct i2c_client *client)
{
return snd_soc_resume_device(&client->dev);
}
#else
#define wm8580_i2c_suspend NULL
#define wm8580_i2c_resume NULL
#endif
static const struct i2c_device_id wm8580_i2c_id[] = {
{ "wm8580", 0 },
{ }
@ -1008,6 +1055,8 @@ static struct i2c_driver wm8580_i2c_driver = {
},
.probe = wm8580_i2c_probe,
.remove = wm8580_i2c_remove,
.suspend = wm8580_i2c_suspend,
.resume = wm8580_i2c_resume,
.id_table = wm8580_i2c_id,
};
#endif

View file

@ -460,6 +460,7 @@ struct snd_soc_dai wm8731_dai = {
};
EXPORT_SYMBOL_GPL(wm8731_dai);
#ifdef CONFIG_PM
static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
@ -488,6 +489,10 @@ static int wm8731_resume(struct platform_device *pdev)
wm8731_set_bias_level(codec, codec->suspend_bias_level);
return 0;
}
#else
#define wm8731_suspend NULL
#define wm8731_resume NULL
#endif
static int wm8731_probe(struct platform_device *pdev)
{
@ -680,6 +685,21 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi)
return 0;
}
#ifdef CONFIG_PM
static int wm8731_spi_suspend(struct spi_device *spi, pm_message_t msg)
{
return snd_soc_suspend_device(&spi->dev);
}
static int wm8731_spi_resume(struct spi_device *spi)
{
return snd_soc_resume_device(&spi->dev);
}
#else
#define wm8731_spi_suspend NULL
#define wm8731_spi_resume NULL
#endif
static struct spi_driver wm8731_spi_driver = {
.driver = {
.name = "wm8731",
@ -687,6 +707,8 @@ static struct spi_driver wm8731_spi_driver = {
.owner = THIS_MODULE,
},
.probe = wm8731_spi_probe,
.suspend = wm8731_spi_suspend,
.resume = wm8731_spi_resume,
.remove = __devexit_p(wm8731_spi_remove),
};
#endif /* CONFIG_SPI_MASTER */
@ -720,6 +742,21 @@ static __devexit int wm8731_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int wm8731_i2c_suspend(struct i2c_client *i2c, pm_message_t msg)
{
return snd_soc_suspend_device(&i2c->dev);
}
static int wm8731_i2c_resume(struct i2c_client *i2c)
{
return snd_soc_resume_device(&i2c->dev);
}
#else
#define wm8731_i2c_suspend NULL
#define wm8731_i2c_resume NULL
#endif
static const struct i2c_device_id wm8731_i2c_id[] = {
{ "wm8731", 0 },
{ }
@ -733,6 +770,8 @@ static struct i2c_driver wm8731_i2c_driver = {
},
.probe = wm8731_i2c_probe,
.remove = __devexit_p(wm8731_i2c_remove),
.suspend = wm8731_i2c_suspend,
.resume = wm8731_i2c_resume,
.id_table = wm8731_i2c_id,
};
#endif

View file

@ -1766,6 +1766,21 @@ static int wm8753_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int wm8753_i2c_suspend(struct i2c_client *client, pm_message_t msg)
{
return snd_soc_suspend_device(&client->dev);
}
static int wm8753_i2c_resume(struct i2c_client *client)
{
return snd_soc_resume_device(&client->dev);
}
#else
#define wm8753_i2c_suspend NULL
#define wm8753_i2c_resume NULL
#endif
static const struct i2c_device_id wm8753_i2c_id[] = {
{ "wm8753", 0 },
{ }
@ -1779,6 +1794,8 @@ static struct i2c_driver wm8753_i2c_driver = {
},
.probe = wm8753_i2c_probe,
.remove = wm8753_i2c_remove,
.suspend = wm8753_i2c_suspend,
.resume = wm8753_i2c_resume,
.id_table = wm8753_i2c_id,
};
#endif
@ -1834,6 +1851,22 @@ static int __devexit wm8753_spi_remove(struct spi_device *spi)
return 0;
}
#ifdef CONFIG_PM
static int wm8753_spi_suspend(struct spi_device *spi, pm_message_t msg)
{
return snd_soc_suspend_device(&spi->dev);
}
static int wm8753_spi_resume(struct spi_device *spi)
{
return snd_soc_resume_device(&spi->dev);
}
#else
#define wm8753_spi_suspend NULL
#define wm8753_spi_resume NULL
#endif
static struct spi_driver wm8753_spi_driver = {
.driver = {
.name = "wm8753",
@ -1842,6 +1875,8 @@ static struct spi_driver wm8753_spi_driver = {
},
.probe = wm8753_spi_probe,
.remove = __devexit_p(wm8753_spi_remove),
.suspend = wm8753_spi_suspend,
.resume = wm8753_spi_resume,
};
#endif

View file

@ -116,6 +116,7 @@
#define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c
#define WM8900_REG_DACCTRL_MUTE 0x004
#define WM8900_REG_DACCTRL_DAC_SB_FILT 0x100
#define WM8900_REG_DACCTRL_AIF_LRCLKRATE 0x400
#define WM8900_REG_AUDIO3_ADCLRC_DIR 0x0800
@ -439,7 +440,6 @@ SOC_SINGLE("DAC Soft Mute Switch", WM8900_REG_DACCTRL, 6, 1, 1),
SOC_ENUM("DAC Mute Rate", dac_mute_rate),
SOC_SINGLE("DAC Mono Switch", WM8900_REG_DACCTRL, 9, 1, 0),
SOC_ENUM("DAC Deemphasis", dac_deemphasis),
SOC_SINGLE("DAC Sloping Stopband Filter Switch", WM8900_REG_DACCTRL, 8, 1, 0),
SOC_SINGLE("DAC Sigma-Delta Modulator Clock Switch", WM8900_REG_DACCTRL,
12, 1, 0),
@ -743,6 +743,17 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
wm8900_write(codec, WM8900_REG_AUDIO1, reg);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
reg = wm8900_read(codec, WM8900_REG_DACCTRL);
if (params_rate(params) <= 24000)
reg |= WM8900_REG_DACCTRL_DAC_SB_FILT;
else
reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT;
wm8900_write(codec, WM8900_REG_DACCTRL, reg);
}
return 0;
}
@ -1388,6 +1399,21 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int wm8900_i2c_suspend(struct i2c_client *client, pm_message_t msg)
{
return snd_soc_suspend_device(&client->dev);
}
static int wm8900_i2c_resume(struct i2c_client *client)
{
return snd_soc_resume_device(&client->dev);
}
#else
#define wm8900_i2c_suspend NULL
#define wm8900_i2c_resume NULL
#endif
static const struct i2c_device_id wm8900_i2c_id[] = {
{ "wm8900", 0 },
{ }
@ -1401,6 +1427,8 @@ static struct i2c_driver wm8900_i2c_driver = {
},
.probe = wm8900_i2c_probe,
.remove = __devexit_p(wm8900_i2c_remove),
.suspend = wm8900_i2c_suspend,
.resume = wm8900_i2c_resume,
.id_table = wm8900_i2c_id,
};

View file

@ -715,8 +715,6 @@ SOC_ENUM("DAC Soft Mute Rate", soft_mute),
SOC_ENUM("DAC Mute Mode", mute_mode),
SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
SOC_ENUM("DAC De-emphasis", dac_deemphasis),
SOC_SINGLE("DAC Sloping Stopband Filter Switch",
WM8903_DAC_DIGITAL_1, 11, 1, 0),
SOC_ENUM("DAC Companding Mode", dac_companding),
SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
@ -1373,12 +1371,19 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3);
u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0);
u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1);
u16 dac_digital1 = wm8903_read(codec, WM8903_DAC_DIGITAL_1);
if (substream == wm8903->slave_substream) {
dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
return 0;
}
/* Enable sloping stopband filter for low sample rates */
if (fs <= 24000)
dac_digital1 |= WM8903_DAC_SB_FILT;
else
dac_digital1 &= ~WM8903_DAC_SB_FILT;
/* Configure sample rate logic for DSP - choose nearest rate */
dsp_config = 0;
best_val = abs(sample_rates[dsp_config].rate - fs);
@ -1503,6 +1508,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1);
wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2);
wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3);
wm8903_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1);
return 0;
}
@ -1721,6 +1727,21 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int wm8903_i2c_suspend(struct i2c_client *client, pm_message_t msg)
{
return snd_soc_suspend_device(&client->dev);
}
static int wm8903_i2c_resume(struct i2c_client *client)
{
return snd_soc_resume_device(&client->dev);
}
#else
#define wm8903_i2c_suspend NULL
#define wm8903_i2c_resume NULL
#endif
/* i2c codec control layer */
static const struct i2c_device_id wm8903_i2c_id[] = {
{ "wm8903", 0 },
@ -1735,6 +1756,8 @@ static struct i2c_driver wm8903_i2c_driver = {
},
.probe = wm8903_i2c_probe,
.remove = __devexit_p(wm8903_i2c_remove),
.suspend = wm8903_i2c_suspend,
.resume = wm8903_i2c_resume,
.id_table = wm8903_i2c_id,
};

View file

@ -916,6 +916,21 @@ static int __devexit wm8940_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int wm8940_i2c_suspend(struct i2c_client *client, pm_message_t msg)
{
return snd_soc_suspend_device(&client->dev);
}
static int wm8940_i2c_resume(struct i2c_client *client)
{
return snd_soc_resume_device(&client->dev);
}
#else
#define wm8940_i2c_suspend NULL
#define wm8940_i2c_resume NULL
#endif
static const struct i2c_device_id wm8940_i2c_id[] = {
{ "wm8940", 0 },
{ }
@ -929,6 +944,8 @@ static struct i2c_driver wm8940_i2c_driver = {
},
.probe = wm8940_i2c_probe,
.remove = __devexit_p(wm8940_i2c_remove),
.suspend = wm8940_i2c_suspend,
.resume = wm8940_i2c_resume,
.id_table = wm8940_i2c_id,
};

View file

@ -927,6 +927,21 @@ static __devexit int wm8960_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int wm8960_i2c_suspend(struct i2c_client *client, pm_message_t msg)
{
return snd_soc_suspend_device(&client->dev);
}
static int wm8960_i2c_resume(struct i2c_client *client)
{
return snd_soc_resume_device(&client->dev);
}
#else
#define wm8960_i2c_suspend NULL
#define wm8960_i2c_resume NULL
#endif
static const struct i2c_device_id wm8960_i2c_id[] = {
{ "wm8960", 0 },
{ }
@ -940,6 +955,8 @@ static struct i2c_driver wm8960_i2c_driver = {
},
.probe = wm8960_i2c_probe,
.remove = __devexit_p(wm8960_i2c_remove),
.suspend = wm8960_i2c_suspend,
.resume = wm8960_i2c_resume,
.id_table = wm8960_i2c_id,
};

1326
sound/soc/codecs/wm8961.c Normal file

File diff suppressed because it is too large Load diff

866
sound/soc/codecs/wm8961.h Normal file
View file

@ -0,0 +1,866 @@
/*
* wm8961.h -- WM8961 Soc Audio driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _WM8961_H
#define _WM8961_H
#include <sound/soc.h>
extern struct snd_soc_codec_device soc_codec_dev_wm8961;
extern struct snd_soc_dai wm8961_dai;
#define WM8961_BCLK 1
#define WM8961_LRCLK 2
#define WM8961_BCLK_DIV_1 0
#define WM8961_BCLK_DIV_1_5 1
#define WM8961_BCLK_DIV_2 2
#define WM8961_BCLK_DIV_3 3
#define WM8961_BCLK_DIV_4 4
#define WM8961_BCLK_DIV_5_5 5
#define WM8961_BCLK_DIV_6 6
#define WM8961_BCLK_DIV_8 7
#define WM8961_BCLK_DIV_11 8
#define WM8961_BCLK_DIV_12 9
#define WM8961_BCLK_DIV_16 10
#define WM8961_BCLK_DIV_24 11
#define WM8961_BCLK_DIV_32 13
/*
* Register values.
*/
#define WM8961_LEFT_INPUT_VOLUME 0x00
#define WM8961_RIGHT_INPUT_VOLUME 0x01
#define WM8961_LOUT1_VOLUME 0x02
#define WM8961_ROUT1_VOLUME 0x03
#define WM8961_CLOCKING1 0x04
#define WM8961_ADC_DAC_CONTROL_1 0x05
#define WM8961_ADC_DAC_CONTROL_2 0x06
#define WM8961_AUDIO_INTERFACE_0 0x07
#define WM8961_CLOCKING2 0x08
#define WM8961_AUDIO_INTERFACE_1 0x09
#define WM8961_LEFT_DAC_VOLUME 0x0A
#define WM8961_RIGHT_DAC_VOLUME 0x0B
#define WM8961_AUDIO_INTERFACE_2 0x0E
#define WM8961_SOFTWARE_RESET 0x0F
#define WM8961_ALC1 0x11
#define WM8961_ALC2 0x12
#define WM8961_ALC3 0x13
#define WM8961_NOISE_GATE 0x14
#define WM8961_LEFT_ADC_VOLUME 0x15
#define WM8961_RIGHT_ADC_VOLUME 0x16
#define WM8961_ADDITIONAL_CONTROL_1 0x17
#define WM8961_ADDITIONAL_CONTROL_2 0x18
#define WM8961_PWR_MGMT_1 0x19
#define WM8961_PWR_MGMT_2 0x1A
#define WM8961_ADDITIONAL_CONTROL_3 0x1B
#define WM8961_ANTI_POP 0x1C
#define WM8961_CLOCKING_3 0x1E
#define WM8961_ADCL_SIGNAL_PATH 0x20
#define WM8961_ADCR_SIGNAL_PATH 0x21
#define WM8961_LOUT2_VOLUME 0x28
#define WM8961_ROUT2_VOLUME 0x29
#define WM8961_PWR_MGMT_3 0x2F
#define WM8961_ADDITIONAL_CONTROL_4 0x30
#define WM8961_CLASS_D_CONTROL_1 0x31
#define WM8961_CLASS_D_CONTROL_2 0x33
#define WM8961_CLOCKING_4 0x38
#define WM8961_DSP_SIDETONE_0 0x39
#define WM8961_DSP_SIDETONE_1 0x3A
#define WM8961_DC_SERVO_0 0x3C
#define WM8961_DC_SERVO_1 0x3D
#define WM8961_DC_SERVO_3 0x3F
#define WM8961_DC_SERVO_5 0x41
#define WM8961_ANALOGUE_PGA_BIAS 0x44
#define WM8961_ANALOGUE_HP_0 0x45
#define WM8961_ANALOGUE_HP_2 0x47
#define WM8961_CHARGE_PUMP_1 0x48
#define WM8961_CHARGE_PUMP_B 0x52
#define WM8961_WRITE_SEQUENCER_1 0x57
#define WM8961_WRITE_SEQUENCER_2 0x58
#define WM8961_WRITE_SEQUENCER_3 0x59
#define WM8961_WRITE_SEQUENCER_4 0x5A
#define WM8961_WRITE_SEQUENCER_5 0x5B
#define WM8961_WRITE_SEQUENCER_6 0x5C
#define WM8961_WRITE_SEQUENCER_7 0x5D
#define WM8961_GENERAL_TEST_1 0xFC
/*
* Field Definitions.
*/
/*
* R0 (0x00) - Left Input volume
*/
#define WM8961_IPVU 0x0100 /* IPVU */
#define WM8961_IPVU_MASK 0x0100 /* IPVU */
#define WM8961_IPVU_SHIFT 8 /* IPVU */
#define WM8961_IPVU_WIDTH 1 /* IPVU */
#define WM8961_LINMUTE 0x0080 /* LINMUTE */
#define WM8961_LINMUTE_MASK 0x0080 /* LINMUTE */
#define WM8961_LINMUTE_SHIFT 7 /* LINMUTE */
#define WM8961_LINMUTE_WIDTH 1 /* LINMUTE */
#define WM8961_LIZC 0x0040 /* LIZC */
#define WM8961_LIZC_MASK 0x0040 /* LIZC */
#define WM8961_LIZC_SHIFT 6 /* LIZC */
#define WM8961_LIZC_WIDTH 1 /* LIZC */
#define WM8961_LINVOL_MASK 0x003F /* LINVOL - [5:0] */
#define WM8961_LINVOL_SHIFT 0 /* LINVOL - [5:0] */
#define WM8961_LINVOL_WIDTH 6 /* LINVOL - [5:0] */
/*
* R1 (0x01) - Right Input volume
*/
#define WM8961_DEVICE_ID_MASK 0xF000 /* DEVICE_ID - [15:12] */
#define WM8961_DEVICE_ID_SHIFT 12 /* DEVICE_ID - [15:12] */
#define WM8961_DEVICE_ID_WIDTH 4 /* DEVICE_ID - [15:12] */
#define WM8961_CHIP_REV_MASK 0x0E00 /* CHIP_REV - [11:9] */
#define WM8961_CHIP_REV_SHIFT 9 /* CHIP_REV - [11:9] */
#define WM8961_CHIP_REV_WIDTH 3 /* CHIP_REV - [11:9] */
#define WM8961_IPVU 0x0100 /* IPVU */
#define WM8961_IPVU_MASK 0x0100 /* IPVU */
#define WM8961_IPVU_SHIFT 8 /* IPVU */
#define WM8961_IPVU_WIDTH 1 /* IPVU */
#define WM8961_RINMUTE 0x0080 /* RINMUTE */
#define WM8961_RINMUTE_MASK 0x0080 /* RINMUTE */
#define WM8961_RINMUTE_SHIFT 7 /* RINMUTE */
#define WM8961_RINMUTE_WIDTH 1 /* RINMUTE */
#define WM8961_RIZC 0x0040 /* RIZC */
#define WM8961_RIZC_MASK 0x0040 /* RIZC */
#define WM8961_RIZC_SHIFT 6 /* RIZC */
#define WM8961_RIZC_WIDTH 1 /* RIZC */
#define WM8961_RINVOL_MASK 0x003F /* RINVOL - [5:0] */
#define WM8961_RINVOL_SHIFT 0 /* RINVOL - [5:0] */
#define WM8961_RINVOL_WIDTH 6 /* RINVOL - [5:0] */
/*
* R2 (0x02) - LOUT1 volume
*/
#define WM8961_OUT1VU 0x0100 /* OUT1VU */
#define WM8961_OUT1VU_MASK 0x0100 /* OUT1VU */
#define WM8961_OUT1VU_SHIFT 8 /* OUT1VU */
#define WM8961_OUT1VU_WIDTH 1 /* OUT1VU */
#define WM8961_LO1ZC 0x0080 /* LO1ZC */
#define WM8961_LO1ZC_MASK 0x0080 /* LO1ZC */
#define WM8961_LO1ZC_SHIFT 7 /* LO1ZC */
#define WM8961_LO1ZC_WIDTH 1 /* LO1ZC */
#define WM8961_LOUT1VOL_MASK 0x007F /* LOUT1VOL - [6:0] */
#define WM8961_LOUT1VOL_SHIFT 0 /* LOUT1VOL - [6:0] */
#define WM8961_LOUT1VOL_WIDTH 7 /* LOUT1VOL - [6:0] */
/*
* R3 (0x03) - ROUT1 volume
*/
#define WM8961_OUT1VU 0x0100 /* OUT1VU */
#define WM8961_OUT1VU_MASK 0x0100 /* OUT1VU */
#define WM8961_OUT1VU_SHIFT 8 /* OUT1VU */
#define WM8961_OUT1VU_WIDTH 1 /* OUT1VU */
#define WM8961_RO1ZC 0x0080 /* RO1ZC */
#define WM8961_RO1ZC_MASK 0x0080 /* RO1ZC */
#define WM8961_RO1ZC_SHIFT 7 /* RO1ZC */
#define WM8961_RO1ZC_WIDTH 1 /* RO1ZC */
#define WM8961_ROUT1VOL_MASK 0x007F /* ROUT1VOL - [6:0] */
#define WM8961_ROUT1VOL_SHIFT 0 /* ROUT1VOL - [6:0] */
#define WM8961_ROUT1VOL_WIDTH 7 /* ROUT1VOL - [6:0] */
/*
* R4 (0x04) - Clocking1
*/
#define WM8961_ADCDIV_MASK 0x01C0 /* ADCDIV - [8:6] */
#define WM8961_ADCDIV_SHIFT 6 /* ADCDIV - [8:6] */
#define WM8961_ADCDIV_WIDTH 3 /* ADCDIV - [8:6] */
#define WM8961_DACDIV_MASK 0x0038 /* DACDIV - [5:3] */
#define WM8961_DACDIV_SHIFT 3 /* DACDIV - [5:3] */
#define WM8961_DACDIV_WIDTH 3 /* DACDIV - [5:3] */
#define WM8961_MCLKDIV 0x0004 /* MCLKDIV */
#define WM8961_MCLKDIV_MASK 0x0004 /* MCLKDIV */
#define WM8961_MCLKDIV_SHIFT 2 /* MCLKDIV */
#define WM8961_MCLKDIV_WIDTH 1 /* MCLKDIV */
/*
* R5 (0x05) - ADC & DAC Control 1
*/
#define WM8961_ADCPOL_MASK 0x0060 /* ADCPOL - [6:5] */
#define WM8961_ADCPOL_SHIFT 5 /* ADCPOL - [6:5] */
#define WM8961_ADCPOL_WIDTH 2 /* ADCPOL - [6:5] */
#define WM8961_DACMU 0x0008 /* DACMU */
#define WM8961_DACMU_MASK 0x0008 /* DACMU */
#define WM8961_DACMU_SHIFT 3 /* DACMU */
#define WM8961_DACMU_WIDTH 1 /* DACMU */
#define WM8961_DEEMPH_MASK 0x0006 /* DEEMPH - [2:1] */
#define WM8961_DEEMPH_SHIFT 1 /* DEEMPH - [2:1] */
#define WM8961_DEEMPH_WIDTH 2 /* DEEMPH - [2:1] */
#define WM8961_ADCHPD 0x0001 /* ADCHPD */
#define WM8961_ADCHPD_MASK 0x0001 /* ADCHPD */
#define WM8961_ADCHPD_SHIFT 0 /* ADCHPD */
#define WM8961_ADCHPD_WIDTH 1 /* ADCHPD */
/*
* R6 (0x06) - ADC & DAC Control 2
*/
#define WM8961_ADC_HPF_CUT_MASK 0x0180 /* ADC_HPF_CUT - [8:7] */
#define WM8961_ADC_HPF_CUT_SHIFT 7 /* ADC_HPF_CUT - [8:7] */
#define WM8961_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [8:7] */
#define WM8961_DACPOL_MASK 0x0060 /* DACPOL - [6:5] */
#define WM8961_DACPOL_SHIFT 5 /* DACPOL - [6:5] */
#define WM8961_DACPOL_WIDTH 2 /* DACPOL - [6:5] */
#define WM8961_DACSMM 0x0008 /* DACSMM */
#define WM8961_DACSMM_MASK 0x0008 /* DACSMM */
#define WM8961_DACSMM_SHIFT 3 /* DACSMM */
#define WM8961_DACSMM_WIDTH 1 /* DACSMM */
#define WM8961_DACMR 0x0004 /* DACMR */
#define WM8961_DACMR_MASK 0x0004 /* DACMR */
#define WM8961_DACMR_SHIFT 2 /* DACMR */
#define WM8961_DACMR_WIDTH 1 /* DACMR */
#define WM8961_DACSLOPE 0x0002 /* DACSLOPE */
#define WM8961_DACSLOPE_MASK 0x0002 /* DACSLOPE */
#define WM8961_DACSLOPE_SHIFT 1 /* DACSLOPE */
#define WM8961_DACSLOPE_WIDTH 1 /* DACSLOPE */
#define WM8961_DAC_OSR128 0x0001 /* DAC_OSR128 */
#define WM8961_DAC_OSR128_MASK 0x0001 /* DAC_OSR128 */
#define WM8961_DAC_OSR128_SHIFT 0 /* DAC_OSR128 */
#define WM8961_DAC_OSR128_WIDTH 1 /* DAC_OSR128 */
/*
* R7 (0x07) - Audio Interface 0
*/
#define WM8961_ALRSWAP 0x0100 /* ALRSWAP */
#define WM8961_ALRSWAP_MASK 0x0100 /* ALRSWAP */
#define WM8961_ALRSWAP_SHIFT 8 /* ALRSWAP */
#define WM8961_ALRSWAP_WIDTH 1 /* ALRSWAP */
#define WM8961_BCLKINV 0x0080 /* BCLKINV */
#define WM8961_BCLKINV_MASK 0x0080 /* BCLKINV */
#define WM8961_BCLKINV_SHIFT 7 /* BCLKINV */
#define WM8961_BCLKINV_WIDTH 1 /* BCLKINV */
#define WM8961_MS 0x0040 /* MS */
#define WM8961_MS_MASK 0x0040 /* MS */
#define WM8961_MS_SHIFT 6 /* MS */
#define WM8961_MS_WIDTH 1 /* MS */
#define WM8961_DLRSWAP 0x0020 /* DLRSWAP */
#define WM8961_DLRSWAP_MASK 0x0020 /* DLRSWAP */
#define WM8961_DLRSWAP_SHIFT 5 /* DLRSWAP */
#define WM8961_DLRSWAP_WIDTH 1 /* DLRSWAP */
#define WM8961_LRP 0x0010 /* LRP */
#define WM8961_LRP_MASK 0x0010 /* LRP */
#define WM8961_LRP_SHIFT 4 /* LRP */
#define WM8961_LRP_WIDTH 1 /* LRP */
#define WM8961_WL_MASK 0x000C /* WL - [3:2] */
#define WM8961_WL_SHIFT 2 /* WL - [3:2] */
#define WM8961_WL_WIDTH 2 /* WL - [3:2] */
#define WM8961_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */
#define WM8961_FORMAT_SHIFT 0 /* FORMAT - [1:0] */
#define WM8961_FORMAT_WIDTH 2 /* FORMAT - [1:0] */
/*
* R8 (0x08) - Clocking2
*/
#define WM8961_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */
#define WM8961_DCLKDIV_SHIFT 6 /* DCLKDIV - [8:6] */
#define WM8961_DCLKDIV_WIDTH 3 /* DCLKDIV - [8:6] */
#define WM8961_CLK_SYS_ENA 0x0020 /* CLK_SYS_ENA */
#define WM8961_CLK_SYS_ENA_MASK 0x0020 /* CLK_SYS_ENA */
#define WM8961_CLK_SYS_ENA_SHIFT 5 /* CLK_SYS_ENA */
#define WM8961_CLK_SYS_ENA_WIDTH 1 /* CLK_SYS_ENA */
#define WM8961_CLK_DSP_ENA 0x0010 /* CLK_DSP_ENA */
#define WM8961_CLK_DSP_ENA_MASK 0x0010 /* CLK_DSP_ENA */
#define WM8961_CLK_DSP_ENA_SHIFT 4 /* CLK_DSP_ENA */
#define WM8961_CLK_DSP_ENA_WIDTH 1 /* CLK_DSP_ENA */
#define WM8961_BCLKDIV_MASK 0x000F /* BCLKDIV - [3:0] */
#define WM8961_BCLKDIV_SHIFT 0 /* BCLKDIV - [3:0] */
#define WM8961_BCLKDIV_WIDTH 4 /* BCLKDIV - [3:0] */
/*
* R9 (0x09) - Audio Interface 1
*/
#define WM8961_DACCOMP_MASK 0x0018 /* DACCOMP - [4:3] */
#define WM8961_DACCOMP_SHIFT 3 /* DACCOMP - [4:3] */
#define WM8961_DACCOMP_WIDTH 2 /* DACCOMP - [4:3] */
#define WM8961_ADCCOMP_MASK 0x0006 /* ADCCOMP - [2:1] */
#define WM8961_ADCCOMP_SHIFT 1 /* ADCCOMP - [2:1] */
#define WM8961_ADCCOMP_WIDTH 2 /* ADCCOMP - [2:1] */
#define WM8961_LOOPBACK 0x0001 /* LOOPBACK */
#define WM8961_LOOPBACK_MASK 0x0001 /* LOOPBACK */
#define WM8961_LOOPBACK_SHIFT 0 /* LOOPBACK */
#define WM8961_LOOPBACK_WIDTH 1 /* LOOPBACK */
/*
* R10 (0x0A) - Left DAC volume
*/
#define WM8961_DACVU 0x0100 /* DACVU */
#define WM8961_DACVU_MASK 0x0100 /* DACVU */
#define WM8961_DACVU_SHIFT 8 /* DACVU */
#define WM8961_DACVU_WIDTH 1 /* DACVU */
#define WM8961_LDACVOL_MASK 0x00FF /* LDACVOL - [7:0] */
#define WM8961_LDACVOL_SHIFT 0 /* LDACVOL - [7:0] */
#define WM8961_LDACVOL_WIDTH 8 /* LDACVOL - [7:0] */
/*
* R11 (0x0B) - Right DAC volume
*/
#define WM8961_DACVU 0x0100 /* DACVU */
#define WM8961_DACVU_MASK 0x0100 /* DACVU */
#define WM8961_DACVU_SHIFT 8 /* DACVU */
#define WM8961_DACVU_WIDTH 1 /* DACVU */
#define WM8961_RDACVOL_MASK 0x00FF /* RDACVOL - [7:0] */
#define WM8961_RDACVOL_SHIFT 0 /* RDACVOL - [7:0] */
#define WM8961_RDACVOL_WIDTH 8 /* RDACVOL - [7:0] */
/*
* R14 (0x0E) - Audio Interface 2
*/
#define WM8961_LRCLK_RATE_MASK 0x01FF /* LRCLK_RATE - [8:0] */
#define WM8961_LRCLK_RATE_SHIFT 0 /* LRCLK_RATE - [8:0] */
#define WM8961_LRCLK_RATE_WIDTH 9 /* LRCLK_RATE - [8:0] */
/*
* R15 (0x0F) - Software Reset
*/
#define WM8961_SW_RST_DEV_ID1_MASK 0xFFFF /* SW_RST_DEV_ID1 - [15:0] */
#define WM8961_SW_RST_DEV_ID1_SHIFT 0 /* SW_RST_DEV_ID1 - [15:0] */
#define WM8961_SW_RST_DEV_ID1_WIDTH 16 /* SW_RST_DEV_ID1 - [15:0] */
/*
* R17 (0x11) - ALC1
*/
#define WM8961_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */
#define WM8961_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */
#define WM8961_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */
#define WM8961_MAXGAIN_MASK 0x0070 /* MAXGAIN - [6:4] */
#define WM8961_MAXGAIN_SHIFT 4 /* MAXGAIN - [6:4] */
#define WM8961_MAXGAIN_WIDTH 3 /* MAXGAIN - [6:4] */
#define WM8961_ALCL_MASK 0x000F /* ALCL - [3:0] */
#define WM8961_ALCL_SHIFT 0 /* ALCL - [3:0] */
#define WM8961_ALCL_WIDTH 4 /* ALCL - [3:0] */
/*
* R18 (0x12) - ALC2
*/
#define WM8961_ALCZC 0x0080 /* ALCZC */
#define WM8961_ALCZC_MASK 0x0080 /* ALCZC */
#define WM8961_ALCZC_SHIFT 7 /* ALCZC */
#define WM8961_ALCZC_WIDTH 1 /* ALCZC */
#define WM8961_MINGAIN_MASK 0x0070 /* MINGAIN - [6:4] */
#define WM8961_MINGAIN_SHIFT 4 /* MINGAIN - [6:4] */
#define WM8961_MINGAIN_WIDTH 3 /* MINGAIN - [6:4] */
#define WM8961_HLD_MASK 0x000F /* HLD - [3:0] */
#define WM8961_HLD_SHIFT 0 /* HLD - [3:0] */
#define WM8961_HLD_WIDTH 4 /* HLD - [3:0] */
/*
* R19 (0x13) - ALC3
*/
#define WM8961_ALCMODE 0x0100 /* ALCMODE */
#define WM8961_ALCMODE_MASK 0x0100 /* ALCMODE */
#define WM8961_ALCMODE_SHIFT 8 /* ALCMODE */
#define WM8961_ALCMODE_WIDTH 1 /* ALCMODE */
#define WM8961_DCY_MASK 0x00F0 /* DCY - [7:4] */
#define WM8961_DCY_SHIFT 4 /* DCY - [7:4] */
#define WM8961_DCY_WIDTH 4 /* DCY - [7:4] */
#define WM8961_ATK_MASK 0x000F /* ATK - [3:0] */
#define WM8961_ATK_SHIFT 0 /* ATK - [3:0] */
#define WM8961_ATK_WIDTH 4 /* ATK - [3:0] */
/*
* R20 (0x14) - Noise Gate
*/
#define WM8961_NGTH_MASK 0x00F8 /* NGTH - [7:3] */
#define WM8961_NGTH_SHIFT 3 /* NGTH - [7:3] */
#define WM8961_NGTH_WIDTH 5 /* NGTH - [7:3] */
#define WM8961_NGG 0x0002 /* NGG */
#define WM8961_NGG_MASK 0x0002 /* NGG */
#define WM8961_NGG_SHIFT 1 /* NGG */
#define WM8961_NGG_WIDTH 1 /* NGG */
#define WM8961_NGAT 0x0001 /* NGAT */
#define WM8961_NGAT_MASK 0x0001 /* NGAT */
#define WM8961_NGAT_SHIFT 0 /* NGAT */
#define WM8961_NGAT_WIDTH 1 /* NGAT */
/*
* R21 (0x15) - Left ADC volume
*/
#define WM8961_ADCVU 0x0100 /* ADCVU */
#define WM8961_ADCVU_MASK 0x0100 /* ADCVU */
#define WM8961_ADCVU_SHIFT 8 /* ADCVU */
#define WM8961_ADCVU_WIDTH 1 /* ADCVU */
#define WM8961_LADCVOL_MASK 0x00FF /* LADCVOL - [7:0] */
#define WM8961_LADCVOL_SHIFT 0 /* LADCVOL - [7:0] */
#define WM8961_LADCVOL_WIDTH 8 /* LADCVOL - [7:0] */
/*
* R22 (0x16) - Right ADC volume
*/
#define WM8961_ADCVU 0x0100 /* ADCVU */
#define WM8961_ADCVU_MASK 0x0100 /* ADCVU */
#define WM8961_ADCVU_SHIFT 8 /* ADCVU */
#define WM8961_ADCVU_WIDTH 1 /* ADCVU */
#define WM8961_RADCVOL_MASK 0x00FF /* RADCVOL - [7:0] */
#define WM8961_RADCVOL_SHIFT 0 /* RADCVOL - [7:0] */
#define WM8961_RADCVOL_WIDTH 8 /* RADCVOL - [7:0] */
/*
* R23 (0x17) - Additional control(1)
*/
#define WM8961_TSDEN 0x0100 /* TSDEN */
#define WM8961_TSDEN_MASK 0x0100 /* TSDEN */
#define WM8961_TSDEN_SHIFT 8 /* TSDEN */
#define WM8961_TSDEN_WIDTH 1 /* TSDEN */
#define WM8961_DMONOMIX 0x0010 /* DMONOMIX */
#define WM8961_DMONOMIX_MASK 0x0010 /* DMONOMIX */
#define WM8961_DMONOMIX_SHIFT 4 /* DMONOMIX */
#define WM8961_DMONOMIX_WIDTH 1 /* DMONOMIX */
#define WM8961_TOEN 0x0001 /* TOEN */
#define WM8961_TOEN_MASK 0x0001 /* TOEN */
#define WM8961_TOEN_SHIFT 0 /* TOEN */
#define WM8961_TOEN_WIDTH 1 /* TOEN */
/*
* R24 (0x18) - Additional control(2)
*/
#define WM8961_TRIS 0x0008 /* TRIS */
#define WM8961_TRIS_MASK 0x0008 /* TRIS */
#define WM8961_TRIS_SHIFT 3 /* TRIS */
#define WM8961_TRIS_WIDTH 1 /* TRIS */
/*
* R25 (0x19) - Pwr Mgmt (1)
*/
#define WM8961_VMIDSEL_MASK 0x0180 /* VMIDSEL - [8:7] */
#define WM8961_VMIDSEL_SHIFT 7 /* VMIDSEL - [8:7] */
#define WM8961_VMIDSEL_WIDTH 2 /* VMIDSEL - [8:7] */
#define WM8961_VREF 0x0040 /* VREF */
#define WM8961_VREF_MASK 0x0040 /* VREF */
#define WM8961_VREF_SHIFT 6 /* VREF */
#define WM8961_VREF_WIDTH 1 /* VREF */
#define WM8961_AINL 0x0020 /* AINL */
#define WM8961_AINL_MASK 0x0020 /* AINL */
#define WM8961_AINL_SHIFT 5 /* AINL */
#define WM8961_AINL_WIDTH 1 /* AINL */
#define WM8961_AINR 0x0010 /* AINR */
#define WM8961_AINR_MASK 0x0010 /* AINR */
#define WM8961_AINR_SHIFT 4 /* AINR */
#define WM8961_AINR_WIDTH 1 /* AINR */
#define WM8961_ADCL 0x0008 /* ADCL */
#define WM8961_ADCL_MASK 0x0008 /* ADCL */
#define WM8961_ADCL_SHIFT 3 /* ADCL */
#define WM8961_ADCL_WIDTH 1 /* ADCL */
#define WM8961_ADCR 0x0004 /* ADCR */
#define WM8961_ADCR_MASK 0x0004 /* ADCR */
#define WM8961_ADCR_SHIFT 2 /* ADCR */
#define WM8961_ADCR_WIDTH 1 /* ADCR */
#define WM8961_MICB 0x0002 /* MICB */
#define WM8961_MICB_MASK 0x0002 /* MICB */
#define WM8961_MICB_SHIFT 1 /* MICB */
#define WM8961_MICB_WIDTH 1 /* MICB */
/*
* R26 (0x1A) - Pwr Mgmt (2)
*/
#define WM8961_DACL 0x0100 /* DACL */
#define WM8961_DACL_MASK 0x0100 /* DACL */
#define WM8961_DACL_SHIFT 8 /* DACL */
#define WM8961_DACL_WIDTH 1 /* DACL */
#define WM8961_DACR 0x0080 /* DACR */
#define WM8961_DACR_MASK 0x0080 /* DACR */
#define WM8961_DACR_SHIFT 7 /* DACR */
#define WM8961_DACR_WIDTH 1 /* DACR */
#define WM8961_LOUT1_PGA 0x0040 /* LOUT1_PGA */
#define WM8961_LOUT1_PGA_MASK 0x0040 /* LOUT1_PGA */
#define WM8961_LOUT1_PGA_SHIFT 6 /* LOUT1_PGA */
#define WM8961_LOUT1_PGA_WIDTH 1 /* LOUT1_PGA */
#define WM8961_ROUT1_PGA 0x0020 /* ROUT1_PGA */
#define WM8961_ROUT1_PGA_MASK 0x0020 /* ROUT1_PGA */
#define WM8961_ROUT1_PGA_SHIFT 5 /* ROUT1_PGA */
#define WM8961_ROUT1_PGA_WIDTH 1 /* ROUT1_PGA */
#define WM8961_SPKL_PGA 0x0010 /* SPKL_PGA */
#define WM8961_SPKL_PGA_MASK 0x0010 /* SPKL_PGA */
#define WM8961_SPKL_PGA_SHIFT 4 /* SPKL_PGA */
#define WM8961_SPKL_PGA_WIDTH 1 /* SPKL_PGA */
#define WM8961_SPKR_PGA 0x0008 /* SPKR_PGA */
#define WM8961_SPKR_PGA_MASK 0x0008 /* SPKR_PGA */
#define WM8961_SPKR_PGA_SHIFT 3 /* SPKR_PGA */
#define WM8961_SPKR_PGA_WIDTH 1 /* SPKR_PGA */
/*
* R27 (0x1B) - Additional Control (3)
*/
#define WM8961_SAMPLE_RATE_MASK 0x0007 /* SAMPLE_RATE - [2:0] */
#define WM8961_SAMPLE_RATE_SHIFT 0 /* SAMPLE_RATE - [2:0] */
#define WM8961_SAMPLE_RATE_WIDTH 3 /* SAMPLE_RATE - [2:0] */
/*
* R28 (0x1C) - Anti-pop
*/
#define WM8961_BUFDCOPEN 0x0010 /* BUFDCOPEN */
#define WM8961_BUFDCOPEN_MASK 0x0010 /* BUFDCOPEN */
#define WM8961_BUFDCOPEN_SHIFT 4 /* BUFDCOPEN */
#define WM8961_BUFDCOPEN_WIDTH 1 /* BUFDCOPEN */
#define WM8961_BUFIOEN 0x0008 /* BUFIOEN */
#define WM8961_BUFIOEN_MASK 0x0008 /* BUFIOEN */
#define WM8961_BUFIOEN_SHIFT 3 /* BUFIOEN */
#define WM8961_BUFIOEN_WIDTH 1 /* BUFIOEN */
#define WM8961_SOFT_ST 0x0004 /* SOFT_ST */
#define WM8961_SOFT_ST_MASK 0x0004 /* SOFT_ST */
#define WM8961_SOFT_ST_SHIFT 2 /* SOFT_ST */
#define WM8961_SOFT_ST_WIDTH 1 /* SOFT_ST */
/*
* R30 (0x1E) - Clocking 3
*/
#define WM8961_CLK_TO_DIV_MASK 0x0180 /* CLK_TO_DIV - [8:7] */
#define WM8961_CLK_TO_DIV_SHIFT 7 /* CLK_TO_DIV - [8:7] */
#define WM8961_CLK_TO_DIV_WIDTH 2 /* CLK_TO_DIV - [8:7] */
#define WM8961_CLK_256K_DIV_MASK 0x007E /* CLK_256K_DIV - [6:1] */
#define WM8961_CLK_256K_DIV_SHIFT 1 /* CLK_256K_DIV - [6:1] */
#define WM8961_CLK_256K_DIV_WIDTH 6 /* CLK_256K_DIV - [6:1] */
#define WM8961_MANUAL_MODE 0x0001 /* MANUAL_MODE */
#define WM8961_MANUAL_MODE_MASK 0x0001 /* MANUAL_MODE */
#define WM8961_MANUAL_MODE_SHIFT 0 /* MANUAL_MODE */
#define WM8961_MANUAL_MODE_WIDTH 1 /* MANUAL_MODE */
/*
* R32 (0x20) - ADCL signal path
*/
#define WM8961_LMICBOOST_MASK 0x0030 /* LMICBOOST - [5:4] */
#define WM8961_LMICBOOST_SHIFT 4 /* LMICBOOST - [5:4] */
#define WM8961_LMICBOOST_WIDTH 2 /* LMICBOOST - [5:4] */
/*
* R33 (0x21) - ADCR signal path
*/
#define WM8961_RMICBOOST_MASK 0x0030 /* RMICBOOST - [5:4] */
#define WM8961_RMICBOOST_SHIFT 4 /* RMICBOOST - [5:4] */
#define WM8961_RMICBOOST_WIDTH 2 /* RMICBOOST - [5:4] */
/*
* R40 (0x28) - LOUT2 volume
*/
#define WM8961_SPKVU 0x0100 /* SPKVU */
#define WM8961_SPKVU_MASK 0x0100 /* SPKVU */
#define WM8961_SPKVU_SHIFT 8 /* SPKVU */
#define WM8961_SPKVU_WIDTH 1 /* SPKVU */
#define WM8961_SPKLZC 0x0080 /* SPKLZC */
#define WM8961_SPKLZC_MASK 0x0080 /* SPKLZC */
#define WM8961_SPKLZC_SHIFT 7 /* SPKLZC */
#define WM8961_SPKLZC_WIDTH 1 /* SPKLZC */
#define WM8961_SPKLVOL_MASK 0x007F /* SPKLVOL - [6:0] */
#define WM8961_SPKLVOL_SHIFT 0 /* SPKLVOL - [6:0] */
#define WM8961_SPKLVOL_WIDTH 7 /* SPKLVOL - [6:0] */
/*
* R41 (0x29) - ROUT2 volume
*/
#define WM8961_SPKVU 0x0100 /* SPKVU */
#define WM8961_SPKVU_MASK 0x0100 /* SPKVU */
#define WM8961_SPKVU_SHIFT 8 /* SPKVU */
#define WM8961_SPKVU_WIDTH 1 /* SPKVU */
#define WM8961_SPKRZC 0x0080 /* SPKRZC */
#define WM8961_SPKRZC_MASK 0x0080 /* SPKRZC */
#define WM8961_SPKRZC_SHIFT 7 /* SPKRZC */
#define WM8961_SPKRZC_WIDTH 1 /* SPKRZC */
#define WM8961_SPKRVOL_MASK 0x007F /* SPKRVOL - [6:0] */
#define WM8961_SPKRVOL_SHIFT 0 /* SPKRVOL - [6:0] */
#define WM8961_SPKRVOL_WIDTH 7 /* SPKRVOL - [6:0] */
/*
* R47 (0x2F) - Pwr Mgmt (3)
*/
#define WM8961_TEMP_SHUT 0x0002 /* TEMP_SHUT */
#define WM8961_TEMP_SHUT_MASK 0x0002 /* TEMP_SHUT */
#define WM8961_TEMP_SHUT_SHIFT 1 /* TEMP_SHUT */
#define WM8961_TEMP_SHUT_WIDTH 1 /* TEMP_SHUT */
#define WM8961_TEMP_WARN 0x0001 /* TEMP_WARN */
#define WM8961_TEMP_WARN_MASK 0x0001 /* TEMP_WARN */
#define WM8961_TEMP_WARN_SHIFT 0 /* TEMP_WARN */
#define WM8961_TEMP_WARN_WIDTH 1 /* TEMP_WARN */
/*
* R48 (0x30) - Additional Control (4)
*/
#define WM8961_TSENSEN 0x0002 /* TSENSEN */
#define WM8961_TSENSEN_MASK 0x0002 /* TSENSEN */
#define WM8961_TSENSEN_SHIFT 1 /* TSENSEN */
#define WM8961_TSENSEN_WIDTH 1 /* TSENSEN */
#define WM8961_MBSEL 0x0001 /* MBSEL */
#define WM8961_MBSEL_MASK 0x0001 /* MBSEL */
#define WM8961_MBSEL_SHIFT 0 /* MBSEL */
#define WM8961_MBSEL_WIDTH 1 /* MBSEL */
/*
* R49 (0x31) - Class D Control 1
*/
#define WM8961_SPKR_ENA 0x0080 /* SPKR_ENA */
#define WM8961_SPKR_ENA_MASK 0x0080 /* SPKR_ENA */
#define WM8961_SPKR_ENA_SHIFT 7 /* SPKR_ENA */
#define WM8961_SPKR_ENA_WIDTH 1 /* SPKR_ENA */
#define WM8961_SPKL_ENA 0x0040 /* SPKL_ENA */
#define WM8961_SPKL_ENA_MASK 0x0040 /* SPKL_ENA */
#define WM8961_SPKL_ENA_SHIFT 6 /* SPKL_ENA */
#define WM8961_SPKL_ENA_WIDTH 1 /* SPKL_ENA */
/*
* R51 (0x33) - Class D Control 2
*/
#define WM8961_CLASSD_ACGAIN_MASK 0x0007 /* CLASSD_ACGAIN - [2:0] */
#define WM8961_CLASSD_ACGAIN_SHIFT 0 /* CLASSD_ACGAIN - [2:0] */
#define WM8961_CLASSD_ACGAIN_WIDTH 3 /* CLASSD_ACGAIN - [2:0] */
/*
* R56 (0x38) - Clocking 4
*/
#define WM8961_CLK_DCS_DIV_MASK 0x01E0 /* CLK_DCS_DIV - [8:5] */
#define WM8961_CLK_DCS_DIV_SHIFT 5 /* CLK_DCS_DIV - [8:5] */
#define WM8961_CLK_DCS_DIV_WIDTH 4 /* CLK_DCS_DIV - [8:5] */
#define WM8961_CLK_SYS_RATE_MASK 0x001E /* CLK_SYS_RATE - [4:1] */
#define WM8961_CLK_SYS_RATE_SHIFT 1 /* CLK_SYS_RATE - [4:1] */
#define WM8961_CLK_SYS_RATE_WIDTH 4 /* CLK_SYS_RATE - [4:1] */
/*
* R57 (0x39) - DSP Sidetone 0
*/
#define WM8961_ADCR_DAC_SVOL_MASK 0x00F0 /* ADCR_DAC_SVOL - [7:4] */
#define WM8961_ADCR_DAC_SVOL_SHIFT 4 /* ADCR_DAC_SVOL - [7:4] */
#define WM8961_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [7:4] */
#define WM8961_ADC_TO_DACR_MASK 0x000C /* ADC_TO_DACR - [3:2] */
#define WM8961_ADC_TO_DACR_SHIFT 2 /* ADC_TO_DACR - [3:2] */
#define WM8961_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [3:2] */
/*
* R58 (0x3A) - DSP Sidetone 1
*/
#define WM8961_ADCL_DAC_SVOL_MASK 0x00F0 /* ADCL_DAC_SVOL - [7:4] */
#define WM8961_ADCL_DAC_SVOL_SHIFT 4 /* ADCL_DAC_SVOL - [7:4] */
#define WM8961_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [7:4] */
#define WM8961_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */
#define WM8961_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */
#define WM8961_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */
/*
* R60 (0x3C) - DC Servo 0
*/
#define WM8961_DCS_ENA_CHAN_INL 0x0080 /* DCS_ENA_CHAN_INL */
#define WM8961_DCS_ENA_CHAN_INL_MASK 0x0080 /* DCS_ENA_CHAN_INL */
#define WM8961_DCS_ENA_CHAN_INL_SHIFT 7 /* DCS_ENA_CHAN_INL */
#define WM8961_DCS_ENA_CHAN_INL_WIDTH 1 /* DCS_ENA_CHAN_INL */
#define WM8961_DCS_TRIG_STARTUP_INL 0x0040 /* DCS_TRIG_STARTUP_INL */
#define WM8961_DCS_TRIG_STARTUP_INL_MASK 0x0040 /* DCS_TRIG_STARTUP_INL */
#define WM8961_DCS_TRIG_STARTUP_INL_SHIFT 6 /* DCS_TRIG_STARTUP_INL */
#define WM8961_DCS_TRIG_STARTUP_INL_WIDTH 1 /* DCS_TRIG_STARTUP_INL */
#define WM8961_DCS_TRIG_SERIES_INL 0x0010 /* DCS_TRIG_SERIES_INL */
#define WM8961_DCS_TRIG_SERIES_INL_MASK 0x0010 /* DCS_TRIG_SERIES_INL */
#define WM8961_DCS_TRIG_SERIES_INL_SHIFT 4 /* DCS_TRIG_SERIES_INL */
#define WM8961_DCS_TRIG_SERIES_INL_WIDTH 1 /* DCS_TRIG_SERIES_INL */
#define WM8961_DCS_ENA_CHAN_INR 0x0008 /* DCS_ENA_CHAN_INR */
#define WM8961_DCS_ENA_CHAN_INR_MASK 0x0008 /* DCS_ENA_CHAN_INR */
#define WM8961_DCS_ENA_CHAN_INR_SHIFT 3 /* DCS_ENA_CHAN_INR */
#define WM8961_DCS_ENA_CHAN_INR_WIDTH 1 /* DCS_ENA_CHAN_INR */
#define WM8961_DCS_TRIG_STARTUP_INR 0x0004 /* DCS_TRIG_STARTUP_INR */
#define WM8961_DCS_TRIG_STARTUP_INR_MASK 0x0004 /* DCS_TRIG_STARTUP_INR */
#define WM8961_DCS_TRIG_STARTUP_INR_SHIFT 2 /* DCS_TRIG_STARTUP_INR */
#define WM8961_DCS_TRIG_STARTUP_INR_WIDTH 1 /* DCS_TRIG_STARTUP_INR */
#define WM8961_DCS_TRIG_SERIES_INR 0x0001 /* DCS_TRIG_SERIES_INR */
#define WM8961_DCS_TRIG_SERIES_INR_MASK 0x0001 /* DCS_TRIG_SERIES_INR */
#define WM8961_DCS_TRIG_SERIES_INR_SHIFT 0 /* DCS_TRIG_SERIES_INR */
#define WM8961_DCS_TRIG_SERIES_INR_WIDTH 1 /* DCS_TRIG_SERIES_INR */
/*
* R61 (0x3D) - DC Servo 1
*/
#define WM8961_DCS_ENA_CHAN_HPL 0x0080 /* DCS_ENA_CHAN_HPL */
#define WM8961_DCS_ENA_CHAN_HPL_MASK 0x0080 /* DCS_ENA_CHAN_HPL */
#define WM8961_DCS_ENA_CHAN_HPL_SHIFT 7 /* DCS_ENA_CHAN_HPL */
#define WM8961_DCS_ENA_CHAN_HPL_WIDTH 1 /* DCS_ENA_CHAN_HPL */
#define WM8961_DCS_TRIG_STARTUP_HPL 0x0040 /* DCS_TRIG_STARTUP_HPL */
#define WM8961_DCS_TRIG_STARTUP_HPL_MASK 0x0040 /* DCS_TRIG_STARTUP_HPL */
#define WM8961_DCS_TRIG_STARTUP_HPL_SHIFT 6 /* DCS_TRIG_STARTUP_HPL */
#define WM8961_DCS_TRIG_STARTUP_HPL_WIDTH 1 /* DCS_TRIG_STARTUP_HPL */
#define WM8961_DCS_TRIG_SERIES_HPL 0x0010 /* DCS_TRIG_SERIES_HPL */
#define WM8961_DCS_TRIG_SERIES_HPL_MASK 0x0010 /* DCS_TRIG_SERIES_HPL */
#define WM8961_DCS_TRIG_SERIES_HPL_SHIFT 4 /* DCS_TRIG_SERIES_HPL */
#define WM8961_DCS_TRIG_SERIES_HPL_WIDTH 1 /* DCS_TRIG_SERIES_HPL */
#define WM8961_DCS_ENA_CHAN_HPR 0x0008 /* DCS_ENA_CHAN_HPR */
#define WM8961_DCS_ENA_CHAN_HPR_MASK 0x0008 /* DCS_ENA_CHAN_HPR */
#define WM8961_DCS_ENA_CHAN_HPR_SHIFT 3 /* DCS_ENA_CHAN_HPR */
#define WM8961_DCS_ENA_CHAN_HPR_WIDTH 1 /* DCS_ENA_CHAN_HPR */
#define WM8961_DCS_TRIG_STARTUP_HPR 0x0004 /* DCS_TRIG_STARTUP_HPR */
#define WM8961_DCS_TRIG_STARTUP_HPR_MASK 0x0004 /* DCS_TRIG_STARTUP_HPR */
#define WM8961_DCS_TRIG_STARTUP_HPR_SHIFT 2 /* DCS_TRIG_STARTUP_HPR */
#define WM8961_DCS_TRIG_STARTUP_HPR_WIDTH 1 /* DCS_TRIG_STARTUP_HPR */
#define WM8961_DCS_TRIG_SERIES_HPR 0x0001 /* DCS_TRIG_SERIES_HPR */
#define WM8961_DCS_TRIG_SERIES_HPR_MASK 0x0001 /* DCS_TRIG_SERIES_HPR */
#define WM8961_DCS_TRIG_SERIES_HPR_SHIFT 0 /* DCS_TRIG_SERIES_HPR */
#define WM8961_DCS_TRIG_SERIES_HPR_WIDTH 1 /* DCS_TRIG_SERIES_HPR */
/*
* R63 (0x3F) - DC Servo 3
*/
#define WM8961_DCS_FILT_BW_SERIES_MASK 0x0030 /* DCS_FILT_BW_SERIES - [5:4] */
#define WM8961_DCS_FILT_BW_SERIES_SHIFT 4 /* DCS_FILT_BW_SERIES - [5:4] */
#define WM8961_DCS_FILT_BW_SERIES_WIDTH 2 /* DCS_FILT_BW_SERIES - [5:4] */
/*
* R65 (0x41) - DC Servo 5
*/
#define WM8961_DCS_SERIES_NO_HP_MASK 0x007F /* DCS_SERIES_NO_HP - [6:0] */
#define WM8961_DCS_SERIES_NO_HP_SHIFT 0 /* DCS_SERIES_NO_HP - [6:0] */
#define WM8961_DCS_SERIES_NO_HP_WIDTH 7 /* DCS_SERIES_NO_HP - [6:0] */
/*
* R68 (0x44) - Analogue PGA Bias
*/
#define WM8961_HP_PGAS_BIAS_MASK 0x0007 /* HP_PGAS_BIAS - [2:0] */
#define WM8961_HP_PGAS_BIAS_SHIFT 0 /* HP_PGAS_BIAS - [2:0] */
#define WM8961_HP_PGAS_BIAS_WIDTH 3 /* HP_PGAS_BIAS - [2:0] */
/*
* R69 (0x45) - Analogue HP 0
*/
#define WM8961_HPL_RMV_SHORT 0x0080 /* HPL_RMV_SHORT */
#define WM8961_HPL_RMV_SHORT_MASK 0x0080 /* HPL_RMV_SHORT */
#define WM8961_HPL_RMV_SHORT_SHIFT 7 /* HPL_RMV_SHORT */
#define WM8961_HPL_RMV_SHORT_WIDTH 1 /* HPL_RMV_SHORT */
#define WM8961_HPL_ENA_OUTP 0x0040 /* HPL_ENA_OUTP */
#define WM8961_HPL_ENA_OUTP_MASK 0x0040 /* HPL_ENA_OUTP */
#define WM8961_HPL_ENA_OUTP_SHIFT 6 /* HPL_ENA_OUTP */
#define WM8961_HPL_ENA_OUTP_WIDTH 1 /* HPL_ENA_OUTP */
#define WM8961_HPL_ENA_DLY 0x0020 /* HPL_ENA_DLY */
#define WM8961_HPL_ENA_DLY_MASK 0x0020 /* HPL_ENA_DLY */
#define WM8961_HPL_ENA_DLY_SHIFT 5 /* HPL_ENA_DLY */
#define WM8961_HPL_ENA_DLY_WIDTH 1 /* HPL_ENA_DLY */
#define WM8961_HPL_ENA 0x0010 /* HPL_ENA */
#define WM8961_HPL_ENA_MASK 0x0010 /* HPL_ENA */
#define WM8961_HPL_ENA_SHIFT 4 /* HPL_ENA */
#define WM8961_HPL_ENA_WIDTH 1 /* HPL_ENA */
#define WM8961_HPR_RMV_SHORT 0x0008 /* HPR_RMV_SHORT */
#define WM8961_HPR_RMV_SHORT_MASK 0x0008 /* HPR_RMV_SHORT */
#define WM8961_HPR_RMV_SHORT_SHIFT 3 /* HPR_RMV_SHORT */
#define WM8961_HPR_RMV_SHORT_WIDTH 1 /* HPR_RMV_SHORT */
#define WM8961_HPR_ENA_OUTP 0x0004 /* HPR_ENA_OUTP */
#define WM8961_HPR_ENA_OUTP_MASK 0x0004 /* HPR_ENA_OUTP */
#define WM8961_HPR_ENA_OUTP_SHIFT 2 /* HPR_ENA_OUTP */
#define WM8961_HPR_ENA_OUTP_WIDTH 1 /* HPR_ENA_OUTP */
#define WM8961_HPR_ENA_DLY 0x0002 /* HPR_ENA_DLY */
#define WM8961_HPR_ENA_DLY_MASK 0x0002 /* HPR_ENA_DLY */
#define WM8961_HPR_ENA_DLY_SHIFT 1 /* HPR_ENA_DLY */
#define WM8961_HPR_ENA_DLY_WIDTH 1 /* HPR_ENA_DLY */
#define WM8961_HPR_ENA 0x0001 /* HPR_ENA */
#define WM8961_HPR_ENA_MASK 0x0001 /* HPR_ENA */
#define WM8961_HPR_ENA_SHIFT 0 /* HPR_ENA */
#define WM8961_HPR_ENA_WIDTH 1 /* HPR_ENA */
/*
* R71 (0x47) - Analogue HP 2
*/
#define WM8961_HPL_VOL_MASK 0x01C0 /* HPL_VOL - [8:6] */
#define WM8961_HPL_VOL_SHIFT 6 /* HPL_VOL - [8:6] */
#define WM8961_HPL_VOL_WIDTH 3 /* HPL_VOL - [8:6] */
#define WM8961_HPR_VOL_MASK 0x0038 /* HPR_VOL - [5:3] */
#define WM8961_HPR_VOL_SHIFT 3 /* HPR_VOL - [5:3] */
#define WM8961_HPR_VOL_WIDTH 3 /* HPR_VOL - [5:3] */
#define WM8961_HP_BIAS_BOOST_MASK 0x0007 /* HP_BIAS_BOOST - [2:0] */
#define WM8961_HP_BIAS_BOOST_SHIFT 0 /* HP_BIAS_BOOST - [2:0] */
#define WM8961_HP_BIAS_BOOST_WIDTH 3 /* HP_BIAS_BOOST - [2:0] */
/*
* R72 (0x48) - Charge Pump 1
*/
#define WM8961_CP_ENA 0x0001 /* CP_ENA */
#define WM8961_CP_ENA_MASK 0x0001 /* CP_ENA */
#define WM8961_CP_ENA_SHIFT 0 /* CP_ENA */
#define WM8961_CP_ENA_WIDTH 1 /* CP_ENA */
/*
* R82 (0x52) - Charge Pump B
*/
#define WM8961_CP_DYN_PWR_MASK 0x0003 /* CP_DYN_PWR - [1:0] */
#define WM8961_CP_DYN_PWR_SHIFT 0 /* CP_DYN_PWR - [1:0] */
#define WM8961_CP_DYN_PWR_WIDTH 2 /* CP_DYN_PWR - [1:0] */
/*
* R87 (0x57) - Write Sequencer 1
*/
#define WM8961_WSEQ_ENA 0x0020 /* WSEQ_ENA */
#define WM8961_WSEQ_ENA_MASK 0x0020 /* WSEQ_ENA */
#define WM8961_WSEQ_ENA_SHIFT 5 /* WSEQ_ENA */
#define WM8961_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */
#define WM8961_WSEQ_WRITE_INDEX_MASK 0x001F /* WSEQ_WRITE_INDEX - [4:0] */
#define WM8961_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [4:0] */
#define WM8961_WSEQ_WRITE_INDEX_WIDTH 5 /* WSEQ_WRITE_INDEX - [4:0] */
/*
* R88 (0x58) - Write Sequencer 2
*/
#define WM8961_WSEQ_EOS 0x0100 /* WSEQ_EOS */
#define WM8961_WSEQ_EOS_MASK 0x0100 /* WSEQ_EOS */
#define WM8961_WSEQ_EOS_SHIFT 8 /* WSEQ_EOS */
#define WM8961_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */
#define WM8961_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */
#define WM8961_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */
#define WM8961_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */
/*
* R89 (0x59) - Write Sequencer 3
*/
#define WM8961_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */
#define WM8961_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */
#define WM8961_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */
/*
* R90 (0x5A) - Write Sequencer 4
*/
#define WM8961_WSEQ_ABORT 0x0100 /* WSEQ_ABORT */
#define WM8961_WSEQ_ABORT_MASK 0x0100 /* WSEQ_ABORT */
#define WM8961_WSEQ_ABORT_SHIFT 8 /* WSEQ_ABORT */
#define WM8961_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */
#define WM8961_WSEQ_START 0x0080 /* WSEQ_START */
#define WM8961_WSEQ_START_MASK 0x0080 /* WSEQ_START */
#define WM8961_WSEQ_START_SHIFT 7 /* WSEQ_START */
#define WM8961_WSEQ_START_WIDTH 1 /* WSEQ_START */
#define WM8961_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */
#define WM8961_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */
#define WM8961_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */
/*
* R91 (0x5B) - Write Sequencer 5
*/
#define WM8961_WSEQ_DATA_WIDTH_MASK 0x0070 /* WSEQ_DATA_WIDTH - [6:4] */
#define WM8961_WSEQ_DATA_WIDTH_SHIFT 4 /* WSEQ_DATA_WIDTH - [6:4] */
#define WM8961_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [6:4] */
#define WM8961_WSEQ_DATA_START_MASK 0x000F /* WSEQ_DATA_START - [3:0] */
#define WM8961_WSEQ_DATA_START_SHIFT 0 /* WSEQ_DATA_START - [3:0] */
#define WM8961_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [3:0] */
/*
* R92 (0x5C) - Write Sequencer 6
*/
#define WM8961_WSEQ_DELAY_MASK 0x000F /* WSEQ_DELAY - [3:0] */
#define WM8961_WSEQ_DELAY_SHIFT 0 /* WSEQ_DELAY - [3:0] */
#define WM8961_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [3:0] */
/*
* R93 (0x5D) - Write Sequencer 7
*/
#define WM8961_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */
#define WM8961_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */
#define WM8961_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */
#define WM8961_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */
/*
* R252 (0xFC) - General test 1
*/
#define WM8961_ARA_ENA 0x0002 /* ARA_ENA */
#define WM8961_ARA_ENA_MASK 0x0002 /* ARA_ENA */
#define WM8961_ARA_ENA_SHIFT 1 /* ARA_ENA */
#define WM8961_ARA_ENA_WIDTH 1 /* ARA_ENA */
#define WM8961_AUTO_INC 0x0001 /* AUTO_INC */
#define WM8961_AUTO_INC_MASK 0x0001 /* AUTO_INC */
#define WM8961_AUTO_INC_SHIFT 0 /* AUTO_INC */
#define WM8961_AUTO_INC_WIDTH 1 /* AUTO_INC */
#endif

View file

@ -981,6 +981,21 @@ static int wm8988_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int wm8988_i2c_suspend(struct i2c_client *client, pm_message_t msg)
{
return snd_soc_suspend_device(&client->dev);
}
static int wm8988_i2c_resume(struct i2c_client *client)
{
return snd_soc_resume_device(&client->dev);
}
#else
#define wm8988_i2c_suspend NULL
#define wm8988_i2c_resume NULL
#endif
static const struct i2c_device_id wm8988_i2c_id[] = {
{ "wm8988", 0 },
{ }
@ -994,6 +1009,8 @@ static struct i2c_driver wm8988_i2c_driver = {
},
.probe = wm8988_i2c_probe,
.remove = wm8988_i2c_remove,
.suspend = wm8988_i2c_suspend,
.resume = wm8988_i2c_resume,
.id_table = wm8988_i2c_id,
};
#endif
@ -1051,6 +1068,21 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi)
return 0;
}
#ifdef CONFIG_PM
static int wm8988_spi_suspend(struct spi_device *spi, pm_message_t msg)
{
return snd_soc_suspend_device(&spi->dev);
}
static int wm8988_spi_resume(struct spi_device *spi)
{
return snd_soc_resume_device(&spi->dev);
}
#else
#define wm8988_spi_suspend NULL
#define wm8988_spi_resume NULL
#endif
static struct spi_driver wm8988_spi_driver = {
.driver = {
.name = "wm8988",
@ -1059,6 +1091,8 @@ static struct spi_driver wm8988_spi_driver = {
},
.probe = wm8988_spi_probe,
.remove = __devexit_p(wm8988_spi_remove),
.suspend = wm8988_spi_suspend,
.resume = wm8988_spi_resume,
};
#endif

View file

@ -1492,6 +1492,21 @@ static __devexit int wm9081_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int wm9081_i2c_suspend(struct i2c_client *client, pm_message_t msg)
{
return snd_soc_suspend_device(&client->dev);
}
static int wm9081_i2c_resume(struct i2c_client *client)
{
return snd_soc_resume_device(&client->dev);
}
#else
#define wm9081_i2c_suspend NULL
#define wm9081_i2c_resume NULL
#endif
static const struct i2c_device_id wm9081_i2c_id[] = {
{ "wm9081", 0 },
{ }
@ -1505,6 +1520,8 @@ static struct i2c_driver wm9081_i2c_driver = {
},
.probe = wm9081_i2c_probe,
.remove = __devexit_p(wm9081_i2c_remove),
.suspend = wm9081_i2c_suspend,
.resume = wm9081_i2c_resume,
.id_table = wm9081_i2c_id,
};

View file

@ -72,4 +72,11 @@ config SND_OMAP_SOC_OMAP3_BEAGLE
help
Say Y if you want to add support for SoC audio on the Beagleboard.
config SND_OMAP_SOC_ZOOM2
tristate "SoC Audio support for Zoom2"
depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2
select SND_OMAP_SOC_MCBSP
select SND_SOC_TWL4030
help
Say Y if you want to add support for Soc audio on Zoom2 board.

View file

@ -14,6 +14,7 @@ snd-soc-omap3evm-objs := omap3evm.o
snd-soc-sdp3430-objs := sdp3430.o
snd-soc-omap3pandora-objs := omap3pandora.o
snd-soc-omap3beagle-objs := omap3beagle.o
snd-soc-zoom2-objs := zoom2.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
obj-$(CONFIG_SND_OMAP_SOC_OSK5912) += snd-soc-osk5912.o
@ -23,3 +24,4 @@ obj-$(CONFIG_MACH_OMAP3EVM) += snd-soc-omap3evm.o
obj-$(CONFIG_SND_OMAP_SOC_SDP3430) += snd-soc-sdp3430.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o
obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o

View file

@ -96,7 +96,7 @@ static int sdp3430_hw_voice_params(struct snd_pcm_substream *substream,
ret = snd_soc_dai_set_fmt(codec_dai,
SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBS_CFM);
SND_SOC_DAIFMT_CBM_CFM);
if (ret) {
printk(KERN_ERR "can't set codec DAI configuration\n");
return ret;

301
sound/soc/omap/zoom2.c Normal file
View file

@ -0,0 +1,301 @@
/*
* zoom2.c -- SoC audio for Zoom2
*
* Author: Misael Lopez Cruz <x0052729@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
#include <mach/mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#include "../codecs/twl4030.h"
#define ZOOM2_HEADSET_MUX_GPIO (OMAP_MAX_GPIO_LINES + 15)
static int zoom2_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int ret;
/* Set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai,
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0) {
printk(KERN_ERR "can't set codec DAI configuration\n");
return ret;
}
/* Set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai,
SND_SOC_DAIFMT_I2S |
SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0) {
printk(KERN_ERR "can't set cpu DAI configuration\n");
return ret;
}
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "can't set codec system clock\n");
return ret;
}
return 0;
}
static struct snd_soc_ops zoom2_ops = {
.hw_params = zoom2_hw_params,
};
static int zoom2_hw_voice_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int ret;
/* Set codec DAI configuration */
ret = snd_soc_dai_set_fmt(codec_dai,
SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret) {
printk(KERN_ERR "can't set codec DAI configuration\n");
return ret;
}
/* Set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai,
SND_SOC_DAIFMT_DSP_A |
SND_SOC_DAIFMT_IB_NF |
SND_SOC_DAIFMT_CBM_CFM);
if (ret < 0) {
printk(KERN_ERR "can't set cpu DAI configuration\n");
return ret;
}
/* Set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
SND_SOC_CLOCK_IN);
if (ret < 0) {
printk(KERN_ERR "can't set codec system clock\n");
return ret;
}
return 0;
}
static struct snd_soc_ops zoom2_voice_ops = {
.hw_params = zoom2_hw_voice_params,
};
/* Zoom2 machine DAPM */
static const struct snd_soc_dapm_widget zoom2_twl4030_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Ext Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_HP("Headset Stereophone", NULL),
SND_SOC_DAPM_LINE("Aux In", NULL),
};
static const struct snd_soc_dapm_route audio_map[] = {
/* External Mics: MAINMIC, SUBMIC with bias*/
{"MAINMIC", NULL, "Mic Bias 1"},
{"SUBMIC", NULL, "Mic Bias 2"},
{"Mic Bias 1", NULL, "Ext Mic"},
{"Mic Bias 2", NULL, "Ext Mic"},
/* External Speakers: HFL, HFR */
{"Ext Spk", NULL, "HFL"},
{"Ext Spk", NULL, "HFR"},
/* Headset Stereophone: HSOL, HSOR */
{"Headset Stereophone", NULL, "HSOL"},
{"Headset Stereophone", NULL, "HSOR"},
/* Headset Mic: HSMIC with bias */
{"HSMIC", NULL, "Headset Mic Bias"},
{"Headset Mic Bias", NULL, "Headset Mic"},
/* Aux In: AUXL, AUXR */
{"Aux In", NULL, "AUXL"},
{"Aux In", NULL, "AUXR"},
};
static int zoom2_twl4030_init(struct snd_soc_codec *codec)
{
int ret;
/* Add Zoom2 specific widgets */
ret = snd_soc_dapm_new_controls(codec, zoom2_twl4030_dapm_widgets,
ARRAY_SIZE(zoom2_twl4030_dapm_widgets));
if (ret)
return ret;
/* Set up Zoom2 specific audio path audio_map */
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
/* Zoom2 connected pins */
snd_soc_dapm_enable_pin(codec, "Ext Mic");
snd_soc_dapm_enable_pin(codec, "Ext Spk");
snd_soc_dapm_enable_pin(codec, "Headset Mic");
snd_soc_dapm_enable_pin(codec, "Headset Stereophone");
snd_soc_dapm_enable_pin(codec, "Aux In");
/* TWL4030 not connected pins */
snd_soc_dapm_nc_pin(codec, "CARKITMIC");
snd_soc_dapm_nc_pin(codec, "DIGIMIC0");
snd_soc_dapm_nc_pin(codec, "DIGIMIC1");
snd_soc_dapm_nc_pin(codec, "OUTL");
snd_soc_dapm_nc_pin(codec, "OUTR");
snd_soc_dapm_nc_pin(codec, "EARPIECE");
snd_soc_dapm_nc_pin(codec, "PREDRIVEL");
snd_soc_dapm_nc_pin(codec, "PREDRIVER");
snd_soc_dapm_nc_pin(codec, "CARKITL");
snd_soc_dapm_nc_pin(codec, "CARKITR");
ret = snd_soc_dapm_sync(codec);
return ret;
}
static int zoom2_twl4030_voice_init(struct snd_soc_codec *codec)
{
unsigned short reg;
/* Enable voice interface */
reg = codec->read(codec, TWL4030_REG_VOICE_IF);
reg |= TWL4030_VIF_DIN_EN | TWL4030_VIF_DOUT_EN | TWL4030_VIF_EN;
codec->write(codec, TWL4030_REG_VOICE_IF, reg);
return 0;
}
/* Digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link zoom2_dai[] = {
{
.name = "TWL4030 I2S",
.stream_name = "TWL4030 Audio",
.cpu_dai = &omap_mcbsp_dai[0],
.codec_dai = &twl4030_dai[TWL4030_DAI_HIFI],
.init = zoom2_twl4030_init,
.ops = &zoom2_ops,
},
{
.name = "TWL4030 PCM",
.stream_name = "TWL4030 Voice",
.cpu_dai = &omap_mcbsp_dai[1],
.codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
.init = zoom2_twl4030_voice_init,
.ops = &zoom2_voice_ops,
},
};
/* Audio machine driver */
static struct snd_soc_card snd_soc_zoom2 = {
.name = "Zoom2",
.platform = &omap_soc_platform,
.dai_link = zoom2_dai,
.num_links = ARRAY_SIZE(zoom2_dai),
};
/* twl4030 setup */
static struct twl4030_setup_data twl4030_setup = {
.ramp_delay_value = 2, /* 81 ms */
.sysclk = 26000,
};
/* Audio subsystem */
static struct snd_soc_device zoom2_snd_devdata = {
.card = &snd_soc_zoom2,
.codec_dev = &soc_codec_dev_twl4030,
.codec_data = &twl4030_setup,
};
static struct platform_device *zoom2_snd_device;
static int __init zoom2_soc_init(void)
{
int ret;
if (!machine_is_omap_zoom2()) {
pr_debug("Not Zoom2!\n");
return -ENODEV;
}
printk(KERN_INFO "Zoom2 SoC init\n");
zoom2_snd_device = platform_device_alloc("soc-audio", -1);
if (!zoom2_snd_device) {
printk(KERN_ERR "Platform device allocation failed\n");
return -ENOMEM;
}
platform_set_drvdata(zoom2_snd_device, &zoom2_snd_devdata);
zoom2_snd_devdata.dev = &zoom2_snd_device->dev;
*(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
*(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
ret = platform_device_add(zoom2_snd_device);
if (ret)
goto err1;
BUG_ON(gpio_request(ZOOM2_HEADSET_MUX_GPIO, "hs_mux") < 0);
gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0);
return 0;
err1:
printk(KERN_ERR "Unable to add platform device\n");
platform_device_put(zoom2_snd_device);
return ret;
}
module_init(zoom2_soc_init);
static void __exit zoom2_soc_exit(void)
{
gpio_free(ZOOM2_HEADSET_MUX_GPIO);
platform_device_unregister(zoom2_snd_device);
}
module_exit(zoom2_soc_exit);
MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
MODULE_DESCRIPTION("ALSA SoC Zoom2");
MODULE_LICENSE("GPL");

View file

@ -20,12 +20,14 @@
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/i2c.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/uda1380.h>
#include <mach/magician.h>
#include <asm/mach-types.h>
@ -447,34 +449,47 @@ static struct snd_soc_card snd_soc_card_magician = {
.platform = &pxa2xx_soc_platform,
};
/* magician audio private data */
static struct uda1380_setup_data magician_uda1380_setup = {
.i2c_address = 0x18,
.dac_clk = UDA1380_DAC_CLK_WSPLL,
};
/* magician audio subsystem */
static struct snd_soc_device magician_snd_devdata = {
.card = &snd_soc_card_magician,
.codec_dev = &soc_codec_dev_uda1380,
.codec_data = &magician_uda1380_setup,
};
static struct platform_device *magician_snd_device;
/*
* FIXME: move into magician board file once merged into the pxa tree
*/
static struct uda1380_platform_data uda1380_info = {
.gpio_power = EGPIO_MAGICIAN_CODEC_POWER,
.gpio_reset = EGPIO_MAGICIAN_CODEC_RESET,
.dac_clk = UDA1380_DAC_CLK_WSPLL,
};
static struct i2c_board_info i2c_board_info[] = {
{
I2C_BOARD_INFO("uda1380", 0x18),
.platform_data = &uda1380_info,
},
};
static int __init magician_init(void)
{
int ret;
struct i2c_adapter *adapter;
struct i2c_client *client;
if (!machine_is_magician())
return -ENODEV;
ret = gpio_request(EGPIO_MAGICIAN_CODEC_POWER, "CODEC_POWER");
if (ret)
goto err_request_power;
ret = gpio_request(EGPIO_MAGICIAN_CODEC_RESET, "CODEC_RESET");
if (ret)
goto err_request_reset;
adapter = i2c_get_adapter(0);
if (!adapter)
return -ENODEV;
client = i2c_new_device(adapter, i2c_board_info);
i2c_put_adapter(adapter);
if (!client)
return -ENODEV;
ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER");
if (ret)
goto err_request_spk;
@ -491,14 +506,8 @@ static int __init magician_init(void)
if (ret)
goto err_request_in_sel1;
gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 1);
gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0);
/* we may need to have the clock running here - pH5 */
gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 1);
udelay(5);
gpio_set_value(EGPIO_MAGICIAN_CODEC_RESET, 0);
magician_snd_device = platform_device_alloc("soc-audio", -1);
if (!magician_snd_device) {
ret = -ENOMEM;
@ -526,10 +535,6 @@ err_request_mic:
err_request_ep:
gpio_free(EGPIO_MAGICIAN_SPK_POWER);
err_request_spk:
gpio_free(EGPIO_MAGICIAN_CODEC_RESET);
err_request_reset:
gpio_free(EGPIO_MAGICIAN_CODEC_POWER);
err_request_power:
return ret;
}
@ -540,15 +545,12 @@ static void __exit magician_exit(void)
gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0);
gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0);
gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0);
gpio_set_value(EGPIO_MAGICIAN_CODEC_POWER, 0);
gpio_free(EGPIO_MAGICIAN_IN_SEL1);
gpio_free(EGPIO_MAGICIAN_IN_SEL0);
gpio_free(EGPIO_MAGICIAN_MIC_POWER);
gpio_free(EGPIO_MAGICIAN_EP_POWER);
gpio_free(EGPIO_MAGICIAN_SPK_POWER);
gpio_free(EGPIO_MAGICIAN_CODEC_RESET);
gpio_free(EGPIO_MAGICIAN_CODEC_POWER);
}
module_init(magician_init);

View file

@ -457,31 +457,27 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
ssp_write_reg(ssp, SSCR0, sscr0);
ssp_write_reg(ssp, SSCR1, sscr1);
ssp_write_reg(ssp, SSPSP, sspsp);
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
sspsp |= SSPSP_SFRMP;
break;
case SND_SOC_DAIFMT_NB_IF:
break;
case SND_SOC_DAIFMT_IB_IF:
sspsp |= SSPSP_SCMODE(2);
break;
case SND_SOC_DAIFMT_IB_NF:
sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
break;
default:
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
sscr0 |= SSCR0_PSP;
sscr1 |= SSCR1_RWOT | SSCR1_TRAIL;
/* See hw_params() */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
sspsp |= SSPSP_SFRMP;
break;
case SND_SOC_DAIFMT_NB_IF:
break;
case SND_SOC_DAIFMT_IB_IF:
sspsp |= SSPSP_SCMODE(2);
break;
case SND_SOC_DAIFMT_IB_NF:
sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
break;
default:
return -EINVAL;
}
break;
case SND_SOC_DAIFMT_DSP_A:
@ -489,22 +485,6 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
case SND_SOC_DAIFMT_DSP_B:
sscr0 |= SSCR0_MOD | SSCR0_PSP;
sscr1 |= SSCR1_TRAIL | SSCR1_RWOT;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
sspsp |= SSPSP_SFRMP;
break;
case SND_SOC_DAIFMT_NB_IF:
break;
case SND_SOC_DAIFMT_IB_IF:
sspsp |= SSPSP_SCMODE(2);
break;
case SND_SOC_DAIFMT_IB_NF:
sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
break;
default:
return -EINVAL;
}
break;
default:

View file

@ -788,6 +788,45 @@ static int soc_resume(struct platform_device *pdev)
return 0;
}
/**
* snd_soc_suspend_device: Notify core of device suspend
*
* @dev: Device being suspended.
*
* In order to ensure that the entire audio subsystem is suspended in a
* coordinated fashion ASoC devices should suspend themselves when
* called by ASoC. When the standard kernel suspend process asks the
* device to suspend it should call this function to initiate a suspend
* of the entire ASoC card.
*
* \note Currently this function is stubbed out.
*/
int snd_soc_suspend_device(struct device *dev)
{
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_suspend_device);
/**
* snd_soc_resume_device: Notify core of device resume
*
* @dev: Device being resumed.
*
* In order to ensure that the entire audio subsystem is resumed in a
* coordinated fashion ASoC devices should resume themselves when called
* by ASoC. When the standard kernel resume process asks the device
* to resume it should call this function. Once all the components of
* the card have notified that they are ready to be resumed the card
* will be resumed.
*
* \note Currently this function is stubbed out.
*/
int snd_soc_resume_device(struct device *dev)
{
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_resume_device);
#else
#define soc_suspend NULL
#define soc_resume NULL
@ -981,6 +1020,21 @@ static int soc_remove(struct platform_device *pdev)
return 0;
}
static void soc_shutdown(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_card *card = socdev->card;
if (!card->instantiated)
return;
/* Flush out pmdown_time work - we actually do want to run it
* now, we're shutting down so no imminent restart. */
run_delayed_work(&card->delayed_work);
snd_soc_dapm_shutdown(socdev);
}
/* ASoC platform driver */
static struct platform_driver soc_driver = {
.driver = {
@ -991,6 +1045,7 @@ static struct platform_driver soc_driver = {
.remove = soc_remove,
.suspend = soc_suspend,
.resume = soc_resume,
.shutdown = soc_shutdown,
};
/* create a new pcm */
@ -1264,10 +1319,10 @@ EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
* Returns 1 for change else 0.
*/
int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg,
unsigned short mask, unsigned short value)
unsigned int mask, unsigned int value)
{
int change;
unsigned short old, new;
unsigned int old, new;
mutex_lock(&io_mutex);
old = snd_soc_read(codec, reg);
@ -1294,10 +1349,10 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits);
* Returns 1 for change else 0.
*/
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg,
unsigned short mask, unsigned short value)
unsigned int mask, unsigned int value)
{
int change;
unsigned short old, new;
unsigned int old, new;
mutex_lock(&io_mutex);
old = snd_soc_read(codec, reg);
@ -1586,7 +1641,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short val, bitmask;
unsigned int val, bitmask;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
;
@ -1615,8 +1670,8 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short val;
unsigned short mask, bitmask;
unsigned int val;
unsigned int mask, bitmask;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
;
@ -1652,7 +1707,7 @@ int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short reg_val, val, mux;
unsigned int reg_val, val, mux;
reg_val = snd_soc_read(codec, e->reg);
val = (reg_val >> e->shift_l) & e->mask;
@ -1691,8 +1746,8 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short val;
unsigned short mask;
unsigned int val;
unsigned int mask;
if (ucontrol->value.enumerated.item[0] > e->max - 1)
return -EINVAL;
@ -1852,7 +1907,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
unsigned short val, val2, val_mask;
unsigned int val, val2, val_mask;
val = (ucontrol->value.integer.value[0] & mask);
if (invert)
@ -1918,7 +1973,7 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
unsigned int reg2 = mc->rreg;
unsigned int shift = mc->shift;
int max = mc->max;
unsigned int mask = (1<<fls(max))-1;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
ucontrol->value.integer.value[0] =
@ -1958,7 +2013,7 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
int err;
unsigned short val, val2, val_mask;
unsigned int val, val2, val_mask;
val_mask = mask << shift;
val = (ucontrol->value.integer.value[0] & mask);
@ -2050,7 +2105,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int reg = mc->reg;
int min = mc->min;
unsigned short val;
unsigned int val;
val = (ucontrol->value.integer.value[0]+min) & 0xff;
val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;

View file

@ -52,19 +52,37 @@
/* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = {
snd_soc_dapm_pre, snd_soc_dapm_supply, snd_soc_dapm_micbias,
snd_soc_dapm_mic, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_mixer_named_ctl,
snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
snd_soc_dapm_post
[snd_soc_dapm_pre] = 0,
[snd_soc_dapm_supply] = 1,
[snd_soc_dapm_micbias] = 2,
[snd_soc_dapm_mic] = 3,
[snd_soc_dapm_mux] = 4,
[snd_soc_dapm_value_mux] = 4,
[snd_soc_dapm_dac] = 5,
[snd_soc_dapm_mixer] = 6,
[snd_soc_dapm_mixer_named_ctl] = 6,
[snd_soc_dapm_pga] = 7,
[snd_soc_dapm_adc] = 8,
[snd_soc_dapm_hp] = 9,
[snd_soc_dapm_spk] = 10,
[snd_soc_dapm_post] = 11,
};
static int dapm_down_seq[] = {
snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
snd_soc_dapm_pga, snd_soc_dapm_mixer_named_ctl, snd_soc_dapm_mixer,
snd_soc_dapm_dac, snd_soc_dapm_mic, snd_soc_dapm_micbias,
snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_supply,
snd_soc_dapm_post
[snd_soc_dapm_pre] = 0,
[snd_soc_dapm_adc] = 1,
[snd_soc_dapm_hp] = 2,
[snd_soc_dapm_spk] = 3,
[snd_soc_dapm_pga] = 4,
[snd_soc_dapm_mixer_named_ctl] = 5,
[snd_soc_dapm_mixer] = 5,
[snd_soc_dapm_dac] = 6,
[snd_soc_dapm_mic] = 7,
[snd_soc_dapm_micbias] = 8,
[snd_soc_dapm_mux] = 9,
[snd_soc_dapm_value_mux] = 9,
[snd_soc_dapm_supply] = 10,
[snd_soc_dapm_post] = 11,
};
static void pop_wait(u32 pop_time)
@ -268,7 +286,7 @@ static int dapm_connect_mixer(struct snd_soc_codec *codec,
static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
{
int change, power;
unsigned short old, new;
unsigned int old, new;
struct snd_soc_codec *codec = widget->codec;
/* check for valid widgets */
@ -689,55 +707,213 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
return power;
}
/*
* Scan a single DAPM widget for a complete audio path and update the
* power status appropriately.
*/
static int dapm_power_widget(struct snd_soc_codec *codec, int event,
struct snd_soc_dapm_widget *w)
static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
struct snd_soc_dapm_widget *b,
int sort[])
{
int ret;
if (sort[a->id] != sort[b->id])
return sort[a->id] - sort[b->id];
if (a->reg != b->reg)
return a->reg - b->reg;
switch (w->id) {
case snd_soc_dapm_pre:
if (!w->event)
return 0;
return 0;
}
if (event == SND_SOC_DAPM_STREAM_START) {
ret = w->event(w,
NULL, SND_SOC_DAPM_PRE_PMU);
if (ret < 0)
return ret;
} else if (event == SND_SOC_DAPM_STREAM_STOP) {
ret = w->event(w,
NULL, SND_SOC_DAPM_PRE_PMD);
if (ret < 0)
return ret;
/* Insert a widget in order into a DAPM power sequence. */
static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
struct list_head *list,
int sort[])
{
struct snd_soc_dapm_widget *w;
list_for_each_entry(w, list, power_list)
if (dapm_seq_compare(new_widget, w, sort) < 0) {
list_add_tail(&new_widget->power_list, &w->power_list);
return;
}
return 0;
case snd_soc_dapm_post:
if (!w->event)
return 0;
list_add_tail(&new_widget->power_list, list);
}
if (event == SND_SOC_DAPM_STREAM_START) {
/* Apply the coalesced changes from a DAPM sequence */
static void dapm_seq_run_coalesced(struct snd_soc_codec *codec,
struct list_head *pending)
{
struct snd_soc_dapm_widget *w;
int reg, power, ret;
unsigned int value = 0;
unsigned int mask = 0;
unsigned int cur_mask;
reg = list_first_entry(pending, struct snd_soc_dapm_widget,
power_list)->reg;
list_for_each_entry(w, pending, power_list) {
cur_mask = 1 << w->shift;
BUG_ON(reg != w->reg);
if (w->invert)
power = !w->power;
else
power = w->power;
mask |= cur_mask;
if (power)
value |= cur_mask;
pop_dbg(codec->pop_time,
"pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
w->name, reg, value, mask);
/* power up pre event */
if (w->power && w->event &&
(w->event_flags & SND_SOC_DAPM_PRE_PMU)) {
pop_dbg(codec->pop_time, "pop test : %s PRE_PMU\n",
w->name);
ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU);
if (ret < 0)
pr_err("%s: pre event failed: %d\n",
w->name, ret);
}
/* power down pre event */
if (!w->power && w->event &&
(w->event_flags & SND_SOC_DAPM_PRE_PMD)) {
pop_dbg(codec->pop_time, "pop test : %s PRE_PMD\n",
w->name);
ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD);
if (ret < 0)
pr_err("%s: pre event failed: %d\n",
w->name, ret);
}
/* Lower PGA volume to reduce pops */
if (w->id == snd_soc_dapm_pga && !w->power)
dapm_set_pga(w, w->power);
}
if (reg >= 0) {
pop_dbg(codec->pop_time,
"pop test : Applying 0x%x/0x%x to %x in %dms\n",
value, mask, reg, codec->pop_time);
pop_wait(codec->pop_time);
snd_soc_update_bits(codec, reg, mask, value);
}
list_for_each_entry(w, pending, power_list) {
/* Raise PGA volume to reduce pops */
if (w->id == snd_soc_dapm_pga && w->power)
dapm_set_pga(w, w->power);
/* power up post event */
if (w->power && w->event &&
(w->event_flags & SND_SOC_DAPM_POST_PMU)) {
pop_dbg(codec->pop_time, "pop test : %s POST_PMU\n",
w->name);
ret = w->event(w,
NULL, SND_SOC_DAPM_POST_PMU);
if (ret < 0)
return ret;
} else if (event == SND_SOC_DAPM_STREAM_STOP) {
ret = w->event(w,
NULL, SND_SOC_DAPM_POST_PMD);
if (ret < 0)
return ret;
pr_err("%s: post event failed: %d\n",
w->name, ret);
}
return 0;
default:
return dapm_generic_apply_power(w);
/* power down post event */
if (!w->power && w->event &&
(w->event_flags & SND_SOC_DAPM_POST_PMD)) {
pop_dbg(codec->pop_time, "pop test : %s POST_PMD\n",
w->name);
ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD);
if (ret < 0)
pr_err("%s: post event failed: %d\n",
w->name, ret);
}
}
}
/* Apply a DAPM power sequence.
*
* We walk over a pre-sorted list of widgets to apply power to. In
* order to minimise the number of writes to the device required
* multiple widgets will be updated in a single write where possible.
* Currently anything that requires more than a single write is not
* handled.
*/
static void dapm_seq_run(struct snd_soc_codec *codec, struct list_head *list,
int event, int sort[])
{
struct snd_soc_dapm_widget *w, *n;
LIST_HEAD(pending);
int cur_sort = -1;
int cur_reg = SND_SOC_NOPM;
int ret;
list_for_each_entry_safe(w, n, list, power_list) {
ret = 0;
/* Do we need to apply any queued changes? */
if (sort[w->id] != cur_sort || w->reg != cur_reg) {
if (!list_empty(&pending))
dapm_seq_run_coalesced(codec, &pending);
INIT_LIST_HEAD(&pending);
cur_sort = -1;
cur_reg = SND_SOC_NOPM;
}
switch (w->id) {
case snd_soc_dapm_pre:
if (!w->event)
list_for_each_entry_safe_continue(w, n, list,
power_list);
if (event == SND_SOC_DAPM_STREAM_START)
ret = w->event(w,
NULL, SND_SOC_DAPM_PRE_PMU);
else if (event == SND_SOC_DAPM_STREAM_STOP)
ret = w->event(w,
NULL, SND_SOC_DAPM_PRE_PMD);
break;
case snd_soc_dapm_post:
if (!w->event)
list_for_each_entry_safe_continue(w, n, list,
power_list);
if (event == SND_SOC_DAPM_STREAM_START)
ret = w->event(w,
NULL, SND_SOC_DAPM_POST_PMU);
else if (event == SND_SOC_DAPM_STREAM_STOP)
ret = w->event(w,
NULL, SND_SOC_DAPM_POST_PMD);
break;
case snd_soc_dapm_input:
case snd_soc_dapm_output:
case snd_soc_dapm_hp:
case snd_soc_dapm_mic:
case snd_soc_dapm_line:
case snd_soc_dapm_spk:
/* No register support currently */
ret = dapm_generic_apply_power(w);
break;
default:
/* Queue it up for application */
cur_sort = sort[w->id];
cur_reg = w->reg;
list_move(&w->power_list, &pending);
break;
}
if (ret < 0)
pr_err("Failed to apply widget power: %d\n",
ret);
}
if (!list_empty(&pending))
dapm_seq_run_coalesced(codec, &pending);
}
/*
* Scan each dapm widget for complete audio path.
* A complete path is a route that has valid endpoints i.e.:-
@ -751,23 +927,22 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
{
struct snd_soc_device *socdev = codec->socdev;
struct snd_soc_dapm_widget *w;
LIST_HEAD(up_list);
LIST_HEAD(down_list);
int ret = 0;
int i, power;
int power;
int sys_power = 0;
INIT_LIST_HEAD(&codec->up_list);
INIT_LIST_HEAD(&codec->down_list);
/* Check which widgets we need to power and store them in
* lists indicating if they should be powered up or down.
*/
list_for_each_entry(w, &codec->dapm_widgets, list) {
switch (w->id) {
case snd_soc_dapm_pre:
list_add_tail(&codec->down_list, &w->power_list);
dapm_seq_insert(w, &down_list, dapm_down_seq);
break;
case snd_soc_dapm_post:
list_add_tail(&codec->up_list, &w->power_list);
dapm_seq_insert(w, &up_list, dapm_up_seq);
break;
default:
@ -782,10 +957,9 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
continue;
if (power)
list_add_tail(&w->power_list, &codec->up_list);
dapm_seq_insert(w, &up_list, dapm_up_seq);
else
list_add_tail(&w->power_list,
&codec->down_list);
dapm_seq_insert(w, &down_list, dapm_down_seq);
w->power = power;
break;
@ -802,32 +976,10 @@ static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
}
/* Power down widgets first; try to avoid amplifying pops. */
for (i = 0; i < ARRAY_SIZE(dapm_down_seq); i++) {
list_for_each_entry(w, &codec->down_list, power_list) {
/* is widget in stream order */
if (w->id != dapm_down_seq[i])
continue;
ret = dapm_power_widget(codec, event, w);
if (ret != 0)
pr_err("Failed to power down %s: %d\n",
w->name, ret);
}
}
dapm_seq_run(codec, &down_list, event, dapm_down_seq);
/* Now power up. */
for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) {
list_for_each_entry(w, &codec->up_list, power_list) {
/* is widget in stream order */
if (w->id != dapm_up_seq[i])
continue;
ret = dapm_power_widget(codec, event, w);
if (ret != 0)
pr_err("Failed to power up %s: %d\n",
w->name, ret);
}
}
dapm_seq_run(codec, &up_list, event, dapm_up_seq);
/* If we just powered the last thing off drop to standby bias */
if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
@ -1372,7 +1524,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
unsigned short val, val2, val_mask;
unsigned int val, val2, val_mask;
int ret;
val = (ucontrol->value.integer.value[0] & mask);
@ -1436,7 +1588,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short val, bitmask;
unsigned int val, bitmask;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
;
@ -1464,8 +1616,8 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short val, mux;
unsigned short mask, bitmask;
unsigned int val, mux;
unsigned int mask, bitmask;
int ret = 0;
for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
@ -1523,7 +1675,7 @@ int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short reg_val, val, mux;
unsigned int reg_val, val, mux;
reg_val = snd_soc_read(widget->codec, e->reg);
val = (reg_val >> e->shift_l) & e->mask;
@ -1563,8 +1715,8 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
{
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned short val, mux;
unsigned short mask;
unsigned int val, mux;
unsigned int mask;
int ret = 0;
if (ucontrol->value.enumerated.item[0] > e->max - 1)
@ -1880,6 +2032,35 @@ void snd_soc_dapm_free(struct snd_soc_device *socdev)
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
/*
* snd_soc_dapm_shutdown - callback for system shutdown
*/
void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
{
struct snd_soc_codec *codec = socdev->card->codec;
struct snd_soc_dapm_widget *w;
LIST_HEAD(down_list);
int powerdown = 0;
list_for_each_entry(w, &codec->dapm_widgets, list) {
if (w->power) {
dapm_seq_insert(w, &down_list, dapm_down_seq);
powerdown = 1;
}
}
/* If there were no widgets to power down we're already in
* standby.
*/
if (powerdown) {
snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE);
dapm_seq_run(codec, &down_list, 0, dapm_down_seq);
snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY);
}
snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
}
/* Module information */
MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");