Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: ASoC: Fix SND_SOC_ALL_CODECS handling of dual SPI and I2C control buses ASoC: Use snd_soc_dapm_nc_pin() in at91sam9g20ek ASoC: TWL4030: Convert the bitfield enums to VALUE_ENUM type ASoC: New enum type: value_enum pxa2xx-ac97: switch AC unit to correct state before probing ASoC: Clocking fixes for davinci-evm.c ASoC: Mark non-connected TWL4030 pins for pandora ASoC: OMAP: Select OMAP pin multiplexing when using Nokia N810 ASoC drivers
This commit is contained in:
commit
932adbed6d
11 changed files with 464 additions and 85 deletions
|
@ -85,6 +85,10 @@
|
|||
#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
|
||||
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
|
||||
#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
|
||||
.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
|
||||
.num_kcontrols = 1}
|
||||
|
||||
/* path domain with event - event handler must return 0 for success */
|
||||
#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
|
||||
|
@ -172,6 +176,12 @@
|
|||
.get = snd_soc_dapm_get_enum_double, \
|
||||
.put = snd_soc_dapm_put_enum_double, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
#define SOC_DAPM_VALUE_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
.info = snd_soc_info_value_enum_double, \
|
||||
.get = snd_soc_dapm_get_value_enum_double, \
|
||||
.put = snd_soc_dapm_put_value_enum_double, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
|
||||
/* dapm stream operations */
|
||||
#define SND_SOC_DAPM_STREAM_NOP 0x0
|
||||
|
@ -214,6 +224,10 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
|
||||
const struct snd_soc_dapm_widget *widget);
|
||||
int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
|
||||
|
@ -247,6 +261,7 @@ enum snd_soc_dapm_type {
|
|||
snd_soc_dapm_input = 0, /* input pin */
|
||||
snd_soc_dapm_output, /* output pin */
|
||||
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
|
||||
snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */
|
||||
snd_soc_dapm_mixer, /* mixes several analog signals together */
|
||||
snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
|
||||
snd_soc_dapm_adc, /* analog to digital converter */
|
||||
|
|
|
@ -94,11 +94,22 @@
|
|||
SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)
|
||||
#define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \
|
||||
{ .max = xmax, .texts = xtexts }
|
||||
#define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \
|
||||
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
|
||||
.mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues}
|
||||
#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \
|
||||
SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues)
|
||||
#define SOC_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
|
||||
.info = snd_soc_info_enum_double, \
|
||||
.get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
#define SOC_VALUE_ENUM(xname, xenum) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
|
||||
.info = snd_soc_info_value_enum_double, \
|
||||
.get = snd_soc_get_value_enum_double, \
|
||||
.put = snd_soc_put_value_enum_double, \
|
||||
.private_value = (unsigned long)&xenum }
|
||||
#define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
|
||||
xhandler_get, xhandler_put) \
|
||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
|
||||
|
@ -200,6 +211,12 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_info_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
|
||||
|
@ -406,6 +423,19 @@ struct soc_enum {
|
|||
void *dapm;
|
||||
};
|
||||
|
||||
/* semi enumerated kcontrol */
|
||||
struct soc_value_enum {
|
||||
unsigned short reg;
|
||||
unsigned short reg2;
|
||||
unsigned char shift_l;
|
||||
unsigned char shift_r;
|
||||
unsigned int max;
|
||||
unsigned int mask;
|
||||
const char **texts;
|
||||
const unsigned int *values;
|
||||
void *dapm;
|
||||
};
|
||||
|
||||
#include <sound/soc-dai.h>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -321,10 +321,6 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
if (cpu_is_pxa25x() || cpu_is_pxa27x()) {
|
||||
pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
|
||||
pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
|
||||
|
@ -339,7 +335,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
|
|||
if (IS_ERR(ac97conf_clk)) {
|
||||
ret = PTR_ERR(ac97conf_clk);
|
||||
ac97conf_clk = NULL;
|
||||
goto err_irq;
|
||||
goto err_conf;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,19 +343,30 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
|
|||
if (IS_ERR(ac97_clk)) {
|
||||
ret = PTR_ERR(ac97_clk);
|
||||
ac97_clk = NULL;
|
||||
goto err_irq;
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
return clk_enable(ac97_clk);
|
||||
ret = clk_enable(ac97_clk);
|
||||
if (ret)
|
||||
goto err_clk2;
|
||||
|
||||
ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
|
||||
if (ret < 0)
|
||||
goto err_irq;
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq:
|
||||
GCR |= GCR_ACLINK_OFF;
|
||||
err_clk2:
|
||||
clk_put(ac97_clk);
|
||||
ac97_clk = NULL;
|
||||
err_clk:
|
||||
if (ac97conf_clk) {
|
||||
clk_put(ac97conf_clk);
|
||||
ac97conf_clk = NULL;
|
||||
}
|
||||
free_irq(IRQ_AC97, NULL);
|
||||
err:
|
||||
err_conf:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);
|
||||
|
|
|
@ -221,8 +221,8 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
|
|||
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
|
||||
|
||||
/* not connected */
|
||||
snd_soc_dapm_disable_pin(codec, "RLINEIN");
|
||||
snd_soc_dapm_disable_pin(codec, "LLINEIN");
|
||||
snd_soc_dapm_nc_pin(codec, "RLINEIN");
|
||||
snd_soc_dapm_nc_pin(codec, "LLINEIN");
|
||||
|
||||
/* always connected */
|
||||
snd_soc_dapm_enable_pin(codec, "Int Mic");
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
# Helper to resolve issues with configs that have SPI enabled but I2C
|
||||
# modular, meaning we can't build the codec driver in with I2C support.
|
||||
# We use an ordered list of conditional defaults to pick the appropriate
|
||||
# setting - SPI can't be modular so that case doesn't need to be covered.
|
||||
config SND_SOC_I2C_AND_SPI
|
||||
tristate
|
||||
default m if I2C=m
|
||||
default y if I2C=y
|
||||
default y if SPI_MASTER=y
|
||||
|
||||
config SND_SOC_ALL_CODECS
|
||||
tristate "Build all ASoC CODEC drivers"
|
||||
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
|
||||
|
@ -14,12 +24,12 @@ config SND_SOC_ALL_CODECS
|
|||
select SND_SOC_UDA134X
|
||||
select SND_SOC_UDA1380 if I2C
|
||||
select SND_SOC_WM8350 if MFD_WM8350
|
||||
select SND_SOC_WM8510 if (I2C || SPI_MASTER)
|
||||
select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8580 if I2C
|
||||
select SND_SOC_WM8728 if (I2C || SPI_MASTER)
|
||||
select SND_SOC_WM8731 if (I2C || SPI_MASTER)
|
||||
select SND_SOC_WM8750 if (I2C || SPI_MASTER)
|
||||
select SND_SOC_WM8753 if (I2C || SPI_MASTER)
|
||||
select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_WM8900 if I2C
|
||||
select SND_SOC_WM8903 if I2C
|
||||
select SND_SOC_WM8971 if I2C
|
||||
|
|
|
@ -192,39 +192,51 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
|
|||
|
||||
/* Earpiece */
|
||||
static const char *twl4030_earpiece_texts[] =
|
||||
{"Off", "DACL1", "DACL2", "Invalid", "DACR1"};
|
||||
{"Off", "DACL1", "DACL2", "DACR1"};
|
||||
|
||||
static const struct soc_enum twl4030_earpiece_enum =
|
||||
SOC_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1,
|
||||
static const unsigned int twl4030_earpiece_values[] =
|
||||
{0x0, 0x1, 0x2, 0x4};
|
||||
|
||||
static const struct soc_value_enum twl4030_earpiece_enum =
|
||||
SOC_VALUE_ENUM_SINGLE(TWL4030_REG_EAR_CTL, 1, 0x7,
|
||||
ARRAY_SIZE(twl4030_earpiece_texts),
|
||||
twl4030_earpiece_texts);
|
||||
twl4030_earpiece_texts,
|
||||
twl4030_earpiece_values);
|
||||
|
||||
static const struct snd_kcontrol_new twl4030_dapm_earpiece_control =
|
||||
SOC_DAPM_ENUM("Route", twl4030_earpiece_enum);
|
||||
SOC_DAPM_VALUE_ENUM("Route", twl4030_earpiece_enum);
|
||||
|
||||
/* PreDrive Left */
|
||||
static const char *twl4030_predrivel_texts[] =
|
||||
{"Off", "DACL1", "DACL2", "Invalid", "DACR2"};
|
||||
{"Off", "DACL1", "DACL2", "DACR2"};
|
||||
|
||||
static const struct soc_enum twl4030_predrivel_enum =
|
||||
SOC_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1,
|
||||
static const unsigned int twl4030_predrivel_values[] =
|
||||
{0x0, 0x1, 0x2, 0x4};
|
||||
|
||||
static const struct soc_value_enum twl4030_predrivel_enum =
|
||||
SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDL_CTL, 1, 0x7,
|
||||
ARRAY_SIZE(twl4030_predrivel_texts),
|
||||
twl4030_predrivel_texts);
|
||||
twl4030_predrivel_texts,
|
||||
twl4030_predrivel_values);
|
||||
|
||||
static const struct snd_kcontrol_new twl4030_dapm_predrivel_control =
|
||||
SOC_DAPM_ENUM("Route", twl4030_predrivel_enum);
|
||||
SOC_DAPM_VALUE_ENUM("Route", twl4030_predrivel_enum);
|
||||
|
||||
/* PreDrive Right */
|
||||
static const char *twl4030_predriver_texts[] =
|
||||
{"Off", "DACR1", "DACR2", "Invalid", "DACL2"};
|
||||
{"Off", "DACR1", "DACR2", "DACL2"};
|
||||
|
||||
static const struct soc_enum twl4030_predriver_enum =
|
||||
SOC_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1,
|
||||
static const unsigned int twl4030_predriver_values[] =
|
||||
{0x0, 0x1, 0x2, 0x4};
|
||||
|
||||
static const struct soc_value_enum twl4030_predriver_enum =
|
||||
SOC_VALUE_ENUM_SINGLE(TWL4030_REG_PREDR_CTL, 1, 0x7,
|
||||
ARRAY_SIZE(twl4030_predriver_texts),
|
||||
twl4030_predriver_texts);
|
||||
twl4030_predriver_texts,
|
||||
twl4030_predriver_values);
|
||||
|
||||
static const struct snd_kcontrol_new twl4030_dapm_predriver_control =
|
||||
SOC_DAPM_ENUM("Route", twl4030_predriver_enum);
|
||||
SOC_DAPM_VALUE_ENUM("Route", twl4030_predriver_enum);
|
||||
|
||||
/* Headset Left */
|
||||
static const char *twl4030_hsol_texts[] =
|
||||
|
@ -300,28 +312,35 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
|
|||
|
||||
/* Left analog microphone selection */
|
||||
static const char *twl4030_analoglmic_texts[] =
|
||||
{"Off", "Main mic", "Headset mic", "Invalid", "AUXL",
|
||||
"Invalid", "Invalid", "Invalid", "Carkit mic"};
|
||||
{"Off", "Main mic", "Headset mic", "AUXL", "Carkit mic"};
|
||||
|
||||
static const struct soc_enum twl4030_analoglmic_enum =
|
||||
SOC_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0,
|
||||
static const unsigned int twl4030_analoglmic_values[] =
|
||||
{0x0, 0x1, 0x2, 0x4, 0x8};
|
||||
|
||||
static const struct soc_value_enum twl4030_analoglmic_enum =
|
||||
SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICL, 0, 0xf,
|
||||
ARRAY_SIZE(twl4030_analoglmic_texts),
|
||||
twl4030_analoglmic_texts);
|
||||
twl4030_analoglmic_texts,
|
||||
twl4030_analoglmic_values);
|
||||
|
||||
static const struct snd_kcontrol_new twl4030_dapm_analoglmic_control =
|
||||
SOC_DAPM_ENUM("Route", twl4030_analoglmic_enum);
|
||||
SOC_DAPM_VALUE_ENUM("Route", twl4030_analoglmic_enum);
|
||||
|
||||
/* Right analog microphone selection */
|
||||
static const char *twl4030_analogrmic_texts[] =
|
||||
{"Off", "Sub mic", "Invalid", "Invalid", "AUXR"};
|
||||
{"Off", "Sub mic", "AUXR"};
|
||||
|
||||
static const struct soc_enum twl4030_analogrmic_enum =
|
||||
SOC_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0,
|
||||
static const unsigned int twl4030_analogrmic_values[] =
|
||||
{0x0, 0x1, 0x4};
|
||||
|
||||
static const struct soc_value_enum twl4030_analogrmic_enum =
|
||||
SOC_VALUE_ENUM_SINGLE(TWL4030_REG_ANAMICR, 0, 0x5,
|
||||
ARRAY_SIZE(twl4030_analogrmic_texts),
|
||||
twl4030_analogrmic_texts);
|
||||
twl4030_analogrmic_texts,
|
||||
twl4030_analogrmic_values);
|
||||
|
||||
static const struct snd_kcontrol_new twl4030_dapm_analogrmic_control =
|
||||
SOC_DAPM_ENUM("Route", twl4030_analogrmic_enum);
|
||||
SOC_DAPM_VALUE_ENUM("Route", twl4030_analogrmic_enum);
|
||||
|
||||
/* TX1 L/R Analog/Digital microphone selection */
|
||||
static const char *twl4030_micpathtx1_texts[] =
|
||||
|
@ -347,28 +366,6 @@ static const struct soc_enum twl4030_micpathtx2_enum =
|
|||
static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control =
|
||||
SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum);
|
||||
|
||||
/*
|
||||
* This function filters out the non valid mux settings, named as "Invalid"
|
||||
* in the enum texts.
|
||||
* Just refuse to set an invalid mux mode.
|
||||
*/
|
||||
static int twl4030_enum_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
int ret = 0;
|
||||
int val;
|
||||
|
||||
val = w->value >> e->shift_l;
|
||||
if (!strcmp("Invalid", e->texts[val])) {
|
||||
printk(KERN_WARNING "Invalid MUX setting on 0x%02x (%d)\n",
|
||||
e->reg, val);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int micpath_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
|
@ -737,16 +734,13 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
|||
|
||||
/* Output MUX controls */
|
||||
/* Earpiece */
|
||||
SND_SOC_DAPM_MUX_E("Earpiece Mux", SND_SOC_NOPM, 0, 0,
|
||||
&twl4030_dapm_earpiece_control, twl4030_enum_event,
|
||||
SND_SOC_DAPM_PRE_REG),
|
||||
SND_SOC_DAPM_VALUE_MUX("Earpiece Mux", SND_SOC_NOPM, 0, 0,
|
||||
&twl4030_dapm_earpiece_control),
|
||||
/* PreDrivL/R */
|
||||
SND_SOC_DAPM_MUX_E("PredriveL Mux", SND_SOC_NOPM, 0, 0,
|
||||
&twl4030_dapm_predrivel_control, twl4030_enum_event,
|
||||
SND_SOC_DAPM_PRE_REG),
|
||||
SND_SOC_DAPM_MUX_E("PredriveR Mux", SND_SOC_NOPM, 0, 0,
|
||||
&twl4030_dapm_predriver_control, twl4030_enum_event,
|
||||
SND_SOC_DAPM_PRE_REG),
|
||||
SND_SOC_DAPM_VALUE_MUX("PredriveL Mux", SND_SOC_NOPM, 0, 0,
|
||||
&twl4030_dapm_predrivel_control),
|
||||
SND_SOC_DAPM_VALUE_MUX("PredriveR Mux", SND_SOC_NOPM, 0, 0,
|
||||
&twl4030_dapm_predriver_control),
|
||||
/* HeadsetL/R */
|
||||
SND_SOC_DAPM_MUX("HeadsetL Mux", SND_SOC_NOPM, 0, 0,
|
||||
&twl4030_dapm_hsol_control),
|
||||
|
@ -789,12 +783,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_POST_REG),
|
||||
|
||||
/* Analog input muxes with power switch for the physical ADCL/R */
|
||||
SND_SOC_DAPM_MUX_E("Analog Left Capture Route",
|
||||
TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control,
|
||||
twl4030_enum_event, SND_SOC_DAPM_PRE_REG),
|
||||
SND_SOC_DAPM_MUX_E("Analog Right Capture Route",
|
||||
TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control,
|
||||
twl4030_enum_event, SND_SOC_DAPM_PRE_REG),
|
||||
SND_SOC_DAPM_VALUE_MUX("Analog Left Capture Route",
|
||||
TWL4030_REG_AVADC_CTL, 3, 0, &twl4030_dapm_analoglmic_control),
|
||||
SND_SOC_DAPM_VALUE_MUX("Analog Right Capture Route",
|
||||
TWL4030_REG_AVADC_CTL, 1, 0, &twl4030_dapm_analogrmic_control),
|
||||
|
||||
SND_SOC_DAPM_PGA("Analog Left Amplifier",
|
||||
TWL4030_REG_ANAMICL, 4, 0, NULL, 0),
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#include "davinci-pcm.h"
|
||||
#include "davinci-i2s.h"
|
||||
|
||||
#define EVM_CODEC_CLOCK 22579200
|
||||
|
||||
#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
|
||||
SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
|
||||
|
@ -37,6 +36,21 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
int ret = 0;
|
||||
unsigned sysclk;
|
||||
|
||||
/* ASP1 on DM355 EVM is clocked by an external oscillator */
|
||||
if (machine_is_davinci_dm355_evm())
|
||||
sysclk = 27000000;
|
||||
|
||||
/* ASP0 in DM6446 EVM is clocked by U55, as configured by
|
||||
* board-dm644x-evm.c using GPIOs from U18. There are six
|
||||
* options; here we "know" we use a 48 KHz sample rate.
|
||||
*/
|
||||
else if (machine_is_davinci_evm())
|
||||
sysclk = 12288000;
|
||||
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
/* set codec DAI configuration */
|
||||
ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT);
|
||||
|
@ -49,8 +63,7 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
|
|||
return ret;
|
||||
|
||||
/* set the codec system clock */
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ config SND_OMAP_SOC_N810
|
|||
tristate "SoC Audio support for Nokia N810"
|
||||
depends on SND_OMAP_SOC && MACH_NOKIA_N810
|
||||
select SND_OMAP_SOC_MCBSP
|
||||
select OMAP_MUX
|
||||
select SND_SOC_TLV320AIC3X
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on Nokia N810.
|
||||
|
|
|
@ -180,6 +180,19 @@ static int omap3pandora_in_init(struct snd_soc_codec *codec)
|
|||
{
|
||||
int ret;
|
||||
|
||||
/* All TWL4030 output pins are floating */
|
||||
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, "HSOL"),
|
||||
snd_soc_dapm_nc_pin(codec, "HSOR"),
|
||||
snd_soc_dapm_nc_pin(codec, "CARKITL"),
|
||||
snd_soc_dapm_nc_pin(codec, "CARKITR"),
|
||||
snd_soc_dapm_nc_pin(codec, "HFL"),
|
||||
snd_soc_dapm_nc_pin(codec, "HFR"),
|
||||
|
||||
ret = snd_soc_dapm_new_controls(codec, omap3pandora_in_dapm_widgets,
|
||||
ARRAY_SIZE(omap3pandora_in_dapm_widgets));
|
||||
if (ret < 0)
|
||||
|
|
|
@ -1584,6 +1584,113 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
|
||||
|
||||
/**
|
||||
* snd_soc_info_value_enum_double - semi enumerated double mixer info callback
|
||||
* @kcontrol: mixer control
|
||||
* @uinfo: control element information
|
||||
*
|
||||
* Callback to provide information about a double semi enumerated
|
||||
* mixer control.
|
||||
*
|
||||
* Semi enumerated mixer: the enumerated items are referred as values. Can be
|
||||
* used for handling bitfield coded enumeration for example.
|
||||
*
|
||||
* Returns 0 for success.
|
||||
*/
|
||||
int snd_soc_info_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
struct soc_value_enum *e = (struct soc_value_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->max;
|
||||
|
||||
if (uinfo->value.enumerated.item > e->max - 1)
|
||||
uinfo->value.enumerated.item = e->max - 1;
|
||||
strcpy(uinfo->value.enumerated.name,
|
||||
e->texts[uinfo->value.enumerated.item]);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_info_value_enum_double);
|
||||
|
||||
/**
|
||||
* snd_soc_get_value_enum_double - semi enumerated double mixer get callback
|
||||
* @kcontrol: mixer control
|
||||
* @ucontrol: control element information
|
||||
*
|
||||
* Callback to get the value of a double semi enumerated mixer.
|
||||
*
|
||||
* Semi enumerated mixer: the enumerated items are referred as values. Can be
|
||||
* used for handling bitfield coded enumeration for example.
|
||||
*
|
||||
* Returns 0 for success.
|
||||
*/
|
||||
int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_value_enum *e = (struct soc_value_enum *)
|
||||
kcontrol->private_value;
|
||||
unsigned short reg_val, val, mux;
|
||||
|
||||
reg_val = snd_soc_read(codec, e->reg);
|
||||
val = (reg_val >> e->shift_l) & e->mask;
|
||||
for (mux = 0; mux < e->max; mux++) {
|
||||
if (val == e->values[mux])
|
||||
break;
|
||||
}
|
||||
ucontrol->value.enumerated.item[0] = mux;
|
||||
if (e->shift_l != e->shift_r) {
|
||||
val = (reg_val >> e->shift_r) & e->mask;
|
||||
for (mux = 0; mux < e->max; mux++) {
|
||||
if (val == e->values[mux])
|
||||
break;
|
||||
}
|
||||
ucontrol->value.enumerated.item[1] = mux;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double);
|
||||
|
||||
/**
|
||||
* snd_soc_put_value_enum_double - semi enumerated double mixer put callback
|
||||
* @kcontrol: mixer control
|
||||
* @ucontrol: control element information
|
||||
*
|
||||
* Callback to set the value of a double semi enumerated mixer.
|
||||
*
|
||||
* Semi enumerated mixer: the enumerated items are referred as values. Can be
|
||||
* used for handling bitfield coded enumeration for example.
|
||||
*
|
||||
* Returns 0 for success.
|
||||
*/
|
||||
int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_value_enum *e = (struct soc_value_enum *)
|
||||
kcontrol->private_value;
|
||||
unsigned short val;
|
||||
unsigned short mask;
|
||||
|
||||
if (ucontrol->value.enumerated.item[0] > e->max - 1)
|
||||
return -EINVAL;
|
||||
val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
|
||||
mask = e->mask << e->shift_l;
|
||||
if (e->shift_l != e->shift_r) {
|
||||
if (ucontrol->value.enumerated.item[1] > e->max - 1)
|
||||
return -EINVAL;
|
||||
val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
|
||||
mask |= e->mask << e->shift_r;
|
||||
}
|
||||
|
||||
return snd_soc_update_bits(codec, e->reg, mask, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
|
||||
|
||||
/**
|
||||
* snd_soc_info_enum_ext - external enumerated single mixer info callback
|
||||
* @kcontrol: mixer control
|
||||
|
|
|
@ -53,13 +53,15 @@
|
|||
/* dapm power sequences - make this per codec in the future */
|
||||
static int dapm_up_seq[] = {
|
||||
snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
|
||||
snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga,
|
||||
snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
|
||||
snd_soc_dapm_mux, snd_soc_dapm_value_mux, snd_soc_dapm_dac,
|
||||
snd_soc_dapm_mixer, snd_soc_dapm_pga, snd_soc_dapm_adc, snd_soc_dapm_hp,
|
||||
snd_soc_dapm_spk, snd_soc_dapm_post
|
||||
};
|
||||
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, snd_soc_dapm_dac, snd_soc_dapm_mic,
|
||||
snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post
|
||||
snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_value_mux,
|
||||
snd_soc_dapm_post
|
||||
};
|
||||
|
||||
static int dapm_status = 1;
|
||||
|
@ -134,6 +136,25 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
|
|||
}
|
||||
}
|
||||
break;
|
||||
case snd_soc_dapm_value_mux: {
|
||||
struct soc_value_enum *e = (struct soc_value_enum *)
|
||||
w->kcontrols[i].private_value;
|
||||
int val, item;
|
||||
|
||||
val = snd_soc_read(w->codec, e->reg);
|
||||
val = (val >> e->shift_l) & e->mask;
|
||||
for (item = 0; item < e->max; item++) {
|
||||
if (val == e->values[item])
|
||||
break;
|
||||
}
|
||||
|
||||
p->connect = 0;
|
||||
for (i = 0; i < e->max; i++) {
|
||||
if (!(strcmp(p->name, e->texts[i])) && item == i)
|
||||
p->connect = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* does not effect routing - always connected */
|
||||
case snd_soc_dapm_pga:
|
||||
case snd_soc_dapm_output:
|
||||
|
@ -179,6 +200,30 @@ static int dapm_connect_mux(struct snd_soc_codec *codec,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* connect value_mux widget to it's interconnecting audio paths */
|
||||
static int dapm_connect_value_mux(struct snd_soc_codec *codec,
|
||||
struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
|
||||
struct snd_soc_dapm_path *path, const char *control_name,
|
||||
const struct snd_kcontrol_new *kcontrol)
|
||||
{
|
||||
struct soc_value_enum *e = (struct soc_value_enum *)
|
||||
kcontrol->private_value;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < e->max; i++) {
|
||||
if (!(strcmp(control_name, e->texts[i]))) {
|
||||
list_add(&path->list, &codec->dapm_paths);
|
||||
list_add(&path->list_sink, &dest->sources);
|
||||
list_add(&path->list_source, &src->sinks);
|
||||
path->name = (char *)e->texts[i];
|
||||
dapm_set_path_status(dest, path, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* connect mixer widget to it's interconnecting audio paths */
|
||||
static int dapm_connect_mixer(struct snd_soc_codec *codec,
|
||||
struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
|
||||
|
@ -653,6 +698,7 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
|
|||
case snd_soc_dapm_vmid:
|
||||
continue;
|
||||
case snd_soc_dapm_mux:
|
||||
case snd_soc_dapm_value_mux:
|
||||
case snd_soc_dapm_output:
|
||||
case snd_soc_dapm_input:
|
||||
case snd_soc_dapm_switch:
|
||||
|
@ -728,6 +774,45 @@ static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* test and update the power status of a value_mux widget */
|
||||
static int dapm_value_mux_update_power(struct snd_soc_dapm_widget *widget,
|
||||
struct snd_kcontrol *kcontrol, int mask,
|
||||
int mux, int val, struct soc_value_enum *e)
|
||||
{
|
||||
struct snd_soc_dapm_path *path;
|
||||
int found = 0;
|
||||
|
||||
if (widget->id != snd_soc_dapm_value_mux)
|
||||
return -ENODEV;
|
||||
|
||||
if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
|
||||
return 0;
|
||||
|
||||
/* find dapm widget path assoc with kcontrol */
|
||||
list_for_each_entry(path, &widget->codec->dapm_paths, list) {
|
||||
if (path->kcontrol != kcontrol)
|
||||
continue;
|
||||
|
||||
if (!path->name || !e->texts[mux])
|
||||
continue;
|
||||
|
||||
found = 1;
|
||||
/* we now need to match the string in the enum to the path */
|
||||
if (!(strcmp(path->name, e->texts[mux])))
|
||||
path->connect = 1; /* new connection */
|
||||
else
|
||||
path->connect = 0; /* old connection must be
|
||||
powered down */
|
||||
}
|
||||
|
||||
if (found) {
|
||||
dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
|
||||
dump_dapm(widget->codec, "mux power update");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* test and update the power status of a mixer or switch widget */
|
||||
static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
|
||||
struct snd_kcontrol *kcontrol, int reg,
|
||||
|
@ -965,6 +1050,12 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
|
|||
if (ret != 0)
|
||||
goto err;
|
||||
break;
|
||||
case snd_soc_dapm_value_mux:
|
||||
ret = dapm_connect_value_mux(codec, wsource, wsink, path,
|
||||
control, &wsink->kcontrols[0]);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
break;
|
||||
case snd_soc_dapm_switch:
|
||||
case snd_soc_dapm_mixer:
|
||||
ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
|
||||
|
@ -1047,6 +1138,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
|
|||
dapm_new_mixer(codec, w);
|
||||
break;
|
||||
case snd_soc_dapm_mux:
|
||||
case snd_soc_dapm_value_mux:
|
||||
dapm_new_mux(codec, w);
|
||||
break;
|
||||
case snd_soc_dapm_adc:
|
||||
|
@ -1273,6 +1365,105 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
|
||||
* callback
|
||||
* @kcontrol: mixer control
|
||||
* @ucontrol: control element information
|
||||
*
|
||||
* Callback to get the value of a dapm semi enumerated double mixer control.
|
||||
*
|
||||
* Semi enumerated mixer: the enumerated items are referred as values. Can be
|
||||
* used for handling bitfield coded enumeration for example.
|
||||
*
|
||||
* Returns 0 for success.
|
||||
*/
|
||||
int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_value_enum *e = (struct soc_value_enum *)
|
||||
kcontrol->private_value;
|
||||
unsigned short reg_val, val, mux;
|
||||
|
||||
reg_val = snd_soc_read(widget->codec, e->reg);
|
||||
val = (reg_val >> e->shift_l) & e->mask;
|
||||
for (mux = 0; mux < e->max; mux++) {
|
||||
if (val == e->values[mux])
|
||||
break;
|
||||
}
|
||||
ucontrol->value.enumerated.item[0] = mux;
|
||||
if (e->shift_l != e->shift_r) {
|
||||
val = (reg_val >> e->shift_r) & e->mask;
|
||||
for (mux = 0; mux < e->max; mux++) {
|
||||
if (val == e->values[mux])
|
||||
break;
|
||||
}
|
||||
ucontrol->value.enumerated.item[1] = mux;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set
|
||||
* callback
|
||||
* @kcontrol: mixer control
|
||||
* @ucontrol: control element information
|
||||
*
|
||||
* Callback to set the value of a dapm semi enumerated double mixer control.
|
||||
*
|
||||
* Semi enumerated mixer: the enumerated items are referred as values. Can be
|
||||
* used for handling bitfield coded enumeration for example.
|
||||
*
|
||||
* Returns 0 for success.
|
||||
*/
|
||||
int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
|
||||
struct soc_value_enum *e = (struct soc_value_enum *)
|
||||
kcontrol->private_value;
|
||||
unsigned short val, mux;
|
||||
unsigned short mask;
|
||||
int ret = 0;
|
||||
|
||||
if (ucontrol->value.enumerated.item[0] > e->max - 1)
|
||||
return -EINVAL;
|
||||
mux = ucontrol->value.enumerated.item[0];
|
||||
val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
|
||||
mask = e->mask << e->shift_l;
|
||||
if (e->shift_l != e->shift_r) {
|
||||
if (ucontrol->value.enumerated.item[1] > e->max - 1)
|
||||
return -EINVAL;
|
||||
val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
|
||||
mask |= e->mask << e->shift_r;
|
||||
}
|
||||
|
||||
mutex_lock(&widget->codec->mutex);
|
||||
widget->value = val;
|
||||
dapm_value_mux_update_power(widget, kcontrol, mask, mux, val, e);
|
||||
if (widget->event) {
|
||||
if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
|
||||
ret = widget->event(widget,
|
||||
kcontrol, SND_SOC_DAPM_PRE_REG);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
|
||||
if (widget->event_flags & SND_SOC_DAPM_POST_REG)
|
||||
ret = widget->event(widget,
|
||||
kcontrol, SND_SOC_DAPM_POST_REG);
|
||||
} else
|
||||
ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
|
||||
|
||||
out:
|
||||
mutex_unlock(&widget->codec->mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_new_control - create new dapm control
|
||||
* @codec: audio codec
|
||||
|
|
Loading…
Reference in a new issue