* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
- * Revision history
- * 12th Aug 2005 Initial version.
- * 25th Oct 2005 Working Codec, Interface and Platform registration.
- *
* TODO:
* o Add hw rules to enforce rates, etc.
* o More testing with other codecs/machines.
#include <linux/pm.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
-#include <sound/driver.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
}
#endif
-static inline const char* get_dai_name(int type)
+static inline const char *get_dai_name(int type)
{
- switch(type) {
+ switch (type) {
case SND_SOC_DAI_AC97_BUS:
case SND_SOC_DAI_AC97:
return "AC97";
/* Check that the codec and cpu DAI's are compatible */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw.rate_min =
- max(codec_dai->playback.rate_min, cpu_dai->playback.rate_min);
+ max(codec_dai->playback.rate_min,
+ cpu_dai->playback.rate_min);
runtime->hw.rate_max =
- min(codec_dai->playback.rate_max, cpu_dai->playback.rate_max);
+ min(codec_dai->playback.rate_max,
+ cpu_dai->playback.rate_max);
runtime->hw.channels_min =
max(codec_dai->playback.channels_min,
cpu_dai->playback.channels_min);
codec_dai->playback.rates & cpu_dai->playback.rates;
} else {
runtime->hw.rate_min =
- max(codec_dai->capture.rate_min, cpu_dai->capture.rate_min);
+ max(codec_dai->capture.rate_min,
+ cpu_dai->capture.rate_min);
runtime->hw.rate_max =
- min(codec_dai->capture.rate_max, cpu_dai->capture.rate_max);
+ min(codec_dai->capture.rate_max,
+ cpu_dai->capture.rate_max);
runtime->hw.channels_min =
max(codec_dai->capture.channels_min,
cpu_dai->capture.channels_min);
goto machine_err;
}
- dbg("asoc: %s <-> %s info:\n",codec_dai->name, cpu_dai->name);
+ dbg("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
dbg("asoc: rate mask 0x%x\n", runtime->hw.rates);
dbg("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
runtime->hw.channels_max);
}
/*
- * Power down the audio subsytem pmdown_time msecs after close is called.
+ * Power down the audio subsystem pmdown_time msecs after close is called.
* This is to ensure there are no pops or clicks in between any music tracks
* due to DAPM power cycling.
*/
int i;
mutex_lock(&pcm_mutex);
- for(i = 0; i < codec->num_dai; i++) {
+ for (i = 0; i < codec->num_dai; i++) {
codec_dai = &codec->dai[i];
dbg("pop wq checking: %s status: %s waiting: %s\n",
/* are we waiting on this codec DAI stream */
if (codec_dai->pop_wait == 1) {
+ /* Reduce power if no longer active */
+ if (codec->active == 0) {
+ dbg("pop wq D1 %s %s\n", codec->name,
+ codec_dai->playback.stream_name);
+ snd_soc_dapm_set_bias_level(socdev,
+ SND_SOC_BIAS_PREPARE);
+ }
+
codec_dai->pop_wait = 0;
- snd_soc_dapm_stream_event(codec, codec_dai->playback.stream_name,
+ snd_soc_dapm_stream_event(codec,
+ codec_dai->playback.stream_name,
SND_SOC_DAPM_STREAM_STOP);
- /* power down the codec power domain if no longer active */
+ /* Fall into standby if no longer active */
if (codec->active == 0) {
dbg("pop wq D3 %s %s\n", codec->name,
codec_dai->playback.stream_name);
- if (codec->dapm_event)
- codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot);
+ snd_soc_dapm_set_bias_level(socdev,
+ SND_SOC_BIAS_STANDBY);
}
}
}
} else {
/* capture streams can be powered down now */
snd_soc_dapm_stream_event(codec,
- codec_dai->capture.stream_name, SND_SOC_DAPM_STREAM_STOP);
+ codec_dai->capture.stream_name,
+ SND_SOC_DAPM_STREAM_STOP);
- if (codec->active == 0 && codec_dai->pop_wait == 0){
- if (codec->dapm_event)
- codec->dapm_event(codec, SNDRV_CTL_POWER_D3hot);
- }
+ if (codec->active == 0 && codec_dai->pop_wait == 0)
+ snd_soc_dapm_set_bias_level(socdev,
+ SND_SOC_BIAS_STANDBY);
}
mutex_unlock(&pcm_mutex);
}
} else {
/* no delayed work - do we need to power up codec */
- if (codec->dapm_state != SNDRV_CTL_POWER_D0) {
+ if (codec->bias_level != SND_SOC_BIAS_ON) {
- if (codec->dapm_event)
- codec->dapm_event(codec, SNDRV_CTL_POWER_D1);
+ snd_soc_dapm_set_bias_level(socdev,
+ SND_SOC_BIAS_PREPARE);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_dapm_stream_event(codec,
codec_dai->capture.stream_name,
SND_SOC_DAPM_STREAM_START);
- if (codec->dapm_event)
- codec->dapm_event(codec, SNDRV_CTL_POWER_D0);
+ snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_ON);
if (codec_dai->dai_ops.digital_mute)
codec_dai->dai_ops.digital_mute(codec_dai, 0);
if (cpu_dai->ops.hw_params) {
ret = cpu_dai->ops.hw_params(substream, params);
if (ret < 0) {
- printk(KERN_ERR "asoc: can't set interface %s hw params\n",
+ printk(KERN_ERR "asoc: interface %s hw params failed\n",
cpu_dai->name);
goto interface_err;
}
if (platform->pcm_ops->hw_params) {
ret = platform->pcm_ops->hw_params(substream, params);
if (ret < 0) {
- printk(KERN_ERR "asoc: can't set platform %s hw params\n",
+ printk(KERN_ERR "asoc: platform %s hw params failed\n",
platform->name);
goto platform_err;
}
codec_dai->ops.hw_free(substream);
codec_err:
- if(machine->ops && machine->ops->hw_free)
+ if (machine->ops && machine->ops->hw_free)
machine->ops->hw_free(substream);
mutex_unlock(&pcm_mutex);
/* powers down audio subsystem for suspend */
static int soc_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_machine *machine = socdev->machine;
- struct snd_soc_platform *platform = socdev->platform;
- struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_machine *machine = socdev->machine;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
struct snd_soc_codec *codec = socdev->codec;
int i;
/* mute any active DAC's */
- for(i = 0; i < machine->num_links; i++) {
+ for (i = 0; i < machine->num_links; i++) {
struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
if (dai->dai_ops.digital_mute && dai->playback.active)
dai->dai_ops.digital_mute(dai, 1);
}
+ /* suspend all pcms */
+ for (i = 0; i < machine->num_links; i++)
+ snd_pcm_suspend_all(machine->dai_link[i].pcm);
+
if (machine->suspend_pre)
machine->suspend_pre(pdev, state);
- for(i = 0; i < machine->num_links; i++) {
+ for (i = 0; i < machine->num_links; i++) {
struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
if (cpu_dai->suspend && cpu_dai->type != SND_SOC_DAI_AC97)
cpu_dai->suspend(pdev, cpu_dai);
/* close any waiting streams and save state */
run_delayed_work(&socdev->delayed_work);
- codec->suspend_dapm_state = codec->dapm_state;
+ codec->suspend_bias_level = codec->bias_level;
- for(i = 0; i < codec->num_dai; i++) {
+ for (i = 0; i < codec->num_dai; i++) {
char *stream = codec->dai[i].playback.stream_name;
if (stream != NULL)
snd_soc_dapm_stream_event(codec, stream,
if (codec_dev->suspend)
codec_dev->suspend(pdev, state);
- for(i = 0; i < machine->num_links; i++) {
+ for (i = 0; i < machine->num_links; i++) {
struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
if (cpu_dai->suspend && cpu_dai->type == SND_SOC_DAI_AC97)
cpu_dai->suspend(pdev, cpu_dai);
/* powers up audio subsystem after a suspend */
static int soc_resume(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_machine *machine = socdev->machine;
- struct snd_soc_platform *platform = socdev->platform;
- struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_machine *machine = socdev->machine;
+ struct snd_soc_platform *platform = socdev->platform;
+ struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
struct snd_soc_codec *codec = socdev->codec;
int i;
if (machine->resume_pre)
machine->resume_pre(pdev);
- for(i = 0; i < machine->num_links; i++) {
+ for (i = 0; i < machine->num_links; i++) {
struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
if (cpu_dai->resume && cpu_dai->type == SND_SOC_DAI_AC97)
cpu_dai->resume(pdev, cpu_dai);
if (codec_dev->resume)
codec_dev->resume(pdev);
- for(i = 0; i < codec->num_dai; i++) {
- char* stream = codec->dai[i].playback.stream_name;
+ for (i = 0; i < codec->num_dai; i++) {
+ char *stream = codec->dai[i].playback.stream_name;
if (stream != NULL)
snd_soc_dapm_stream_event(codec, stream,
SND_SOC_DAPM_STREAM_RESUME);
SND_SOC_DAPM_STREAM_RESUME);
}
- /* unmute any active DAC's */
- for(i = 0; i < machine->num_links; i++) {
+ /* unmute any active DACs */
+ for (i = 0; i < machine->num_links; i++) {
struct snd_soc_codec_dai *dai = machine->dai_link[i].codec_dai;
if (dai->dai_ops.digital_mute && dai->playback.active)
dai->dai_ops.digital_mute(dai, 0);
}
- for(i = 0; i < machine->num_links; i++) {
+ for (i = 0; i < machine->num_links; i++) {
struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
if (cpu_dai->resume && cpu_dai->type != SND_SOC_DAI_AC97)
cpu_dai->resume(pdev, cpu_dai);
if (machine->probe) {
ret = machine->probe(pdev);
- if(ret < 0)
+ if (ret < 0)
return ret;
}
for (i = 0; i < machine->num_links; i++) {
struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
if (cpu_dai->probe) {
- ret = cpu_dai->probe(pdev);
- if(ret < 0)
+ ret = cpu_dai->probe(pdev, cpu_dai);
+ if (ret < 0)
goto cpu_dai_err;
}
}
if (codec_dev->probe) {
ret = codec_dev->probe(pdev);
- if(ret < 0)
+ if (ret < 0)
goto cpu_dai_err;
}
if (platform->probe) {
ret = platform->probe(pdev);
- if(ret < 0)
+ if (ret < 0)
goto platform_err;
}
for (i--; i >= 0; i--) {
struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
if (cpu_dai->remove)
- cpu_dai->remove(pdev);
+ cpu_dai->remove(pdev, cpu_dai);
}
if (machine->remove)
for (i = 0; i < machine->num_links; i++) {
struct snd_soc_cpu_dai *cpu_dai = machine->dai_link[i].cpu_dai;
if (cpu_dai->remove)
- cpu_dai->remove(pdev);
+ cpu_dai->remove(pdev, cpu_dai);
}
if (machine->remove)
static struct platform_driver soc_driver = {
.driver = {
.name = "soc-audio",
+ .owner = THIS_MODULE,
},
.probe = soc_probe,
.remove = soc_remove,
codec_dai->codec = socdev->codec;
/* check client and interface hw capabilities */
- sprintf(new_name, "%s %s-%s-%d",dai_link->stream_name, codec_dai->name,
+ sprintf(new_name, "%s %s-%s-%d", dai_link->stream_name, codec_dai->name,
get_dai_name(cpu_dai->type), num);
if (codec_dai->playback.channels_min)
ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,
capture, &pcm);
if (ret < 0) {
- printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
+ printk(KERN_ERR "asoc: can't create pcm for codec %s\n",
+ codec->name);
kfree(rtd);
return ret;
}
+ dai_link->pcm = pcm;
pcm->private_data = rtd;
soc_pcm_ops.mmap = socdev->platform->pcm_ops->mmap;
soc_pcm_ops.pointer = socdev->platform->pcm_ops->pointer;
step = codec->reg_cache_step;
count += sprintf(buf, "%s registers\n", codec->name);
- for(i = 0; i < codec->reg_cache_size; i += step)
- count += sprintf(buf + count, "%2x: %4x\n", i, codec->read(codec, i));
+ for (i = 0; i < codec->reg_cache_size; i += step)
+ count += sprintf(buf + count, "%2x: %4x\n", i,
+ codec->read(codec, i));
return count;
}
strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
/* create the pcms */
- for(i = 0; i < machine->num_links; i++) {
+ for (i = 0; i < machine->num_links; i++) {
ret = soc_new_pcm(socdev, &machine->dai_link[i], i);
if (ret < 0) {
printk(KERN_ERR "asoc: can't create pcm %s\n",
struct snd_soc_machine *machine = socdev->machine;
int ret = 0, i, ac97 = 0, err = 0;
- mutex_lock(&codec->mutex);
- for(i = 0; i < machine->num_links; i++) {
+ for (i = 0; i < machine->num_links; i++) {
if (socdev->machine->dai_link[i].init) {
err = socdev->machine->dai_link[i].init(codec);
if (err < 0) {
continue;
}
}
- if (socdev->machine->dai_link[i].codec_dai->type ==
+ if (socdev->machine->dai_link[i].codec_dai->type ==
SND_SOC_DAI_AC97_BUS)
ac97 = 1;
}
ret = snd_card_register(codec->card);
if (ret < 0) {
- printk(KERN_ERR "asoc: failed to register soundcard for codec %s\n",
+ printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
codec->name);
goto out;
}
+ mutex_lock(&codec->mutex);
#ifdef CONFIG_SND_SOC_AC97_BUS
if (ac97) {
ret = soc_ac97_dev_register(codec);
if (ret < 0) {
printk(KERN_ERR "asoc: AC97 device register failed\n");
snd_card_free(codec->card);
+ mutex_unlock(&codec->mutex);
goto out;
}
}
err = device_create_file(socdev->dev, &dev_attr_codec_reg);
if (err < 0)
- printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n");
-out:
+ printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
+
mutex_unlock(&codec->mutex);
+
+out:
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_card);
mutex_lock(&codec->mutex);
#ifdef CONFIG_SND_SOC_AC97_BUS
- for(i = 0; i < codec->num_dai; i++) {
+ for (i = 0; i < codec->num_dai; i++) {
codec_dai = &codec->dai[i];
if (codec_dai->type == SND_SOC_DAI_AC97_BUS && codec->ac97) {
soc_ac97_dev_unregister(codec);
memcpy(&template, _template, sizeof(template));
if (long_name)
template.name = long_name;
- template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
template.index = 0;
return snd_ctl_new1(&template, data);
for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
;
val = snd_soc_read(codec, e->reg);
- ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
+ ucontrol->value.enumerated.item[0]
+ = (val >> e->shift_l) & (bitmask - 1);
if (e->shift_l != e->shift_r)
ucontrol->value.enumerated.item[1] =
(val >> e->shift_r) & (bitmask - 1);
int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- int mask = kcontrol->private_value;
+ int max = kcontrol->private_value;
+
+ if (max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->type =
- mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
+ uinfo->value.integer.max = max;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- int mask = (kcontrol->private_value >> 16) & 0xff;
+ int max = (kcontrol->private_value >> 16) & 0xff;
int shift = (kcontrol->private_value >> 8) & 0x0f;
int rshift = (kcontrol->private_value >> 12) & 0x0f;
- uinfo->type =
- mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
+ if (max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
uinfo->count = shift == rshift ? 1 : 2;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
+ uinfo->value.integer.max = max;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0x0f;
int rshift = (kcontrol->private_value >> 12) & 0x0f;
- int mask = (kcontrol->private_value >> 16) & 0xff;
+ int max = (kcontrol->private_value >> 16) & 0xff;
+ int mask = (1 << fls(max)) - 1;
int invert = (kcontrol->private_value >> 24) & 0x01;
ucontrol->value.integer.value[0] =
(snd_soc_read(codec, reg) >> rshift) & mask;
if (invert) {
ucontrol->value.integer.value[0] =
- mask - ucontrol->value.integer.value[0];
+ max - ucontrol->value.integer.value[0];
if (shift != rshift)
ucontrol->value.integer.value[1] =
- mask - ucontrol->value.integer.value[1];
+ max - ucontrol->value.integer.value[1];
}
return 0;
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0x0f;
int rshift = (kcontrol->private_value >> 12) & 0x0f;
- int mask = (kcontrol->private_value >> 16) & 0xff;
+ int max = (kcontrol->private_value >> 16) & 0xff;
+ int mask = (1 << fls(max)) - 1;
int invert = (kcontrol->private_value >> 24) & 0x01;
- int err;
unsigned short val, val2, val_mask;
val = (ucontrol->value.integer.value[0] & mask);
if (invert)
- val = mask - val;
+ val = max - val;
val_mask = mask << shift;
val = val << shift;
if (shift != rshift) {
val2 = (ucontrol->value.integer.value[1] & mask);
if (invert)
- val2 = mask - val2;
+ val2 = max - val2;
val_mask |= mask << rshift;
val |= val2 << rshift;
}
- err = snd_soc_update_bits(codec, reg, val_mask, val);
- return err;
+ return snd_soc_update_bits(codec, reg, val_mask, val);
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- int mask = (kcontrol->private_value >> 12) & 0xff;
+ int max = (kcontrol->private_value >> 12) & 0xff;
+
+ if (max == 1)
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->type =
- mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
- uinfo->value.integer.max = mask;
+ uinfo->value.integer.max = max;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r);
int reg = kcontrol->private_value & 0xff;
int reg2 = (kcontrol->private_value >> 24) & 0xff;
int shift = (kcontrol->private_value >> 8) & 0x0f;
- int mask = (kcontrol->private_value >> 12) & 0xff;
+ int max = (kcontrol->private_value >> 12) & 0xff;
+ int mask = (1<<fls(max))-1;
int invert = (kcontrol->private_value >> 20) & 0x01;
ucontrol->value.integer.value[0] =
(snd_soc_read(codec, reg2) >> shift) & mask;
if (invert) {
ucontrol->value.integer.value[0] =
- mask - ucontrol->value.integer.value[0];
+ max - ucontrol->value.integer.value[0];
ucontrol->value.integer.value[1] =
- mask - ucontrol->value.integer.value[1];
+ max - ucontrol->value.integer.value[1];
}
return 0;
int reg = kcontrol->private_value & 0xff;
int reg2 = (kcontrol->private_value >> 24) & 0xff;
int shift = (kcontrol->private_value >> 8) & 0x0f;
- int mask = (kcontrol->private_value >> 12) & 0xff;
+ int max = (kcontrol->private_value >> 12) & 0xff;
+ int mask = (1 << fls(max)) - 1;
int invert = (kcontrol->private_value >> 20) & 0x01;
int err;
unsigned short val, val2, val_mask;
val2 = (ucontrol->value.integer.value[1] & mask);
if (invert) {
- val = mask - val;
- val2 = mask - val2;
+ val = max - val;
+ val2 = max - val2;
}
val = val << shift;
val2 = val2 << shift;
- if ((err = snd_soc_update_bits(codec, reg, val_mask, val)) < 0)
+ err = snd_soc_update_bits(codec, reg, val_mask, val);
+ if (err < 0)
return err;
err = snd_soc_update_bits(codec, reg2, val_mask, val2);
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r);
+/**
+ * snd_soc_info_volsw_s8 - signed mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a signed mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ int max = (signed char)((kcontrol->private_value >> 16) & 0xff);
+ int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = max-min;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8);
+
+/**
+ * snd_soc_get_volsw_s8 - signed mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to get the value of a signed mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+ int val = snd_soc_read(codec, reg);
+
+ ucontrol->value.integer.value[0] =
+ ((signed char)(val & 0xff))-min;
+ ucontrol->value.integer.value[1] =
+ ((signed char)((val >> 8) & 0xff))-min;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8);
+
+/**
+ * snd_soc_put_volsw_sgn - signed mixer put callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a signed mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int reg = kcontrol->private_value & 0xff;
+ int min = (signed char)((kcontrol->private_value >> 24) & 0xff);
+ unsigned short val;
+
+ val = (ucontrol->value.integer.value[0]+min) & 0xff;
+ val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
+
+ return snd_soc_update_bits(codec, reg, 0xffff, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
+
static int __devinit snd_soc_init(void)
{
printk(KERN_INFO "ASoC version %s\n", SND_SOC_VERSION);
static void snd_soc_exit(void)
{
- platform_driver_unregister(&soc_driver);
+ platform_driver_unregister(&soc_driver);
}
module_init(snd_soc_init);
MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
MODULE_DESCRIPTION("ALSA SoC Core");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-audio");