📄 wm8782-mixer.c
字号:
/*
*
* wm8782-mixer.c
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.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>
#include <sound/initval.h>
#include <sound/control.h>
#include "wm8782-mixer.h"
#include "wm8782.h"
static DEFINE_MUTEX(io_mutex);
/**
* snd_wm8782_update_bits - update codec register bits
* @codec: audio codec
* @reg: codec register
* @mask: register mask
* @value: new value
*
* Writes new register value.
*
* Returns 1 for change else 0.
*/
static int snd_wm8782_update_bits(struct wm8782_platform_data *pdata ,unsigned short reg,unsigned short mask, unsigned short value)
{
int change;
unsigned short old, new;
mutex_lock(&io_mutex);
old = pdata->read( reg);
new = (old & ~mask) | value;
change = old != new;
if (change)
pdata->write( reg, new);
mutex_unlock(&io_mutex);
return change;
}
//EXPORT_SYMBOL_GPL(snd_wm8782_update_bits);
/**
* snd_wm8782_info_volsw - single mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information about a single mixer control.
*
* Returns 0 for success.
*/
int snd_wm8782_info_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
int mask = (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;
uinfo->count = shift == rshift ? 1 : 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = mask;
return 0;
}
EXPORT_SYMBOL_GPL(snd_wm8782_info_volsw);
/**
* snd_wm8782_get_volsw - single mixer get callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to get the value of a single mixer control.
*
* Returns 0 for success.
*/
int snd_wm8782_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct wm8782_platform_data * pdata = snd_kcontrol_chip(kcontrol);
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 invert = (kcontrol->private_value >> 24) & 0x01;
ucontrol->value.integer.value[0] =
(pdata->read(reg) >> shift) & mask;
if (shift != rshift)
ucontrol->value.integer.value[1] =
(pdata->read( reg) >> rshift) & mask;
if (invert) {
ucontrol->value.integer.value[0] =
mask - ucontrol->value.integer.value[0];
if (shift != rshift)
ucontrol->value.integer.value[1] =
mask - ucontrol->value.integer.value[1];
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_wm8782_get_volsw);
/**
* snd_wm8782_put_volsw - single mixer put callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to set the value of a single mixer control.
*
* Returns 0 for success.
*/
int snd_wm8782_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct wm8782_platform_data * pdata = snd_kcontrol_chip(kcontrol);
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 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_mask = mask << shift;
val = val << shift;
if (shift != rshift) {
val2 = (ucontrol->value.integer.value[1] & mask);
if (invert)
val2 = mask - val2;
val_mask |= mask << rshift;
val |= val2 << rshift;
}
err = snd_wm8782_update_bits(pdata,reg, val_mask, val);
return err;
}
EXPORT_SYMBOL_GPL(snd_wm8782_put_volsw);
/**
* snd_wm8782_info_volsw_2r - double mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information about a double mixer control that
* spans 2 codec registers.
*
* Returns 0 for success.
*/
int snd_wm8782_info_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
int mask = (kcontrol->private_value >> 12) & 0xff;
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;
return 0;
}
EXPORT_SYMBOL_GPL(snd_wm8782_info_volsw_2r);
/**
* snd_wm8782_get_volsw_2r - double mixer get callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to get the value of a double mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
int snd_wm8782_get_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct wm8782_platform_data * pdata = snd_kcontrol_chip(kcontrol);
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 invert = (kcontrol->private_value >> 20) & 0x01;
ucontrol->value.integer.value[0] =
(pdata->read( reg) >> shift) & mask;
ucontrol->value.integer.value[1] =
(pdata->read(reg2) >> shift) & mask;
if (invert) {
ucontrol->value.integer.value[0] =
mask - ucontrol->value.integer.value[0];
ucontrol->value.integer.value[1] =
mask - ucontrol->value.integer.value[1];
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_wm8782_get_volsw_2r);
/**
* snd_wm8782_put_volsw_2r - double mixer set callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to set the value of a double mixer control that spans 2 registers.
*
* Returns 0 for success.
*/
int snd_wm8782_put_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct wm8782_platform_data * pdata = snd_kcontrol_chip(kcontrol);
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 invert = (kcontrol->private_value >> 20) & 0x01;
int err;
unsigned short val, val2, val_mask;
val_mask = mask << shift;
val = (ucontrol->value.integer.value[0] & mask);
val2 = (ucontrol->value.integer.value[1] & mask);
if (invert) {
val = mask - val;
val2 = mask - val2;
}
val = val << shift;
val2 = val2 << shift;
if ((err = snd_wm8782_update_bits(pdata,reg, val_mask, val)) < 0)
return err;
err = snd_wm8782_update_bits(pdata,reg2, val_mask, val2);
return err;
}
EXPORT_SYMBOL_GPL(snd_wm8782_put_volsw_2r);
/**
* snd_wm8782_info_enum_double - enumerated double mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to provide information about a double enumerated
* mixer control.
*
* Returns 0 for success.
*/
int snd_wm8782_info_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct snd_wm8782_enum *e = (struct snd_wm8782_enum *)kcontrol->private_value;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
uinfo->value.enumerated.items = e->mask;
if (uinfo->value.enumerated.item > e->mask - 1)
uinfo->value.enumerated.item = e->mask - 1;
strcpy(uinfo->value.enumerated.name,
e->texts[uinfo->value.enumerated.item]);
return 0;
}
EXPORT_SYMBOL_GPL(snd_wm8782_info_enum_double);
/**
* snd_wm8782_get_enum_double - enumerated double mixer get callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to get the value of a double enumerated mixer.
*
* Returns 0 for success.
*/
int snd_wm8782_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct wm8782_platform_data * pdata = snd_kcontrol_chip(kcontrol);
struct snd_wm8782_enum *e = (struct snd_wm8782_enum *)kcontrol->private_value;
unsigned short val, bitmask;
for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
;
val = pdata->read( e->reg);
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);
return 0;
}
EXPORT_SYMBOL_GPL(snd_wm8782_get_enum_double);
/**
* snd_wm8782_put_enum_double - enumerated double mixer put callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Callback to set the value of a double enumerated mixer.
*
* Returns 0 for success.
*/
int snd_wm8782_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct wm8782_platform_data * pdata = snd_kcontrol_chip(kcontrol);
struct snd_wm8782_enum *e = (struct snd_wm8782_enum *)kcontrol->private_value;
unsigned short val;
unsigned short mask, bitmask;
for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
;
if (ucontrol->value.enumerated.item[0] > e->mask - 1)
return -EINVAL;
val = ucontrol->value.enumerated.item[0] << e->shift_l;
mask = (bitmask - 1) << e->shift_l;
if (e->shift_l != e->shift_r) {
if (ucontrol->value.enumerated.item[1] > e->mask - 1)
return -EINVAL;
val |= ucontrol->value.enumerated.item[1] << e->shift_r;
mask |= (bitmask - 1) << e->shift_r;
}
return snd_wm8782_update_bits(pdata,e->reg, mask, val);
}
EXPORT_SYMBOL_GPL(snd_wm8782_put_enum_double);
static int __init snd_wm8782_mixer_init(void)
{
printk(KERN_INFO "WM8782 MIXER module loaded successfully\n");
return 0;
}
static void snd_wm8782_mixer_exit(void)
{
printk(KERN_INFO "WM8782 MIXER module unloaded successfully\n");
}
module_init(snd_wm8782_mixer_init);
module_exit(snd_wm8782_mixer_exit);
/* Module information */
MODULE_AUTHOR("Sitek Hengke Electronic LTD.CO");
MODULE_DESCRIPTION("WM8782 ALSA MIXER");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -