Merge branch 'topic/asoc' into for-linus
Conflicts: sound/soc/codecs/ad1938.c
此提交包含在:
@@ -124,6 +124,8 @@ struct twl4030_priv {
|
||||
struct snd_soc_codec codec;
|
||||
|
||||
unsigned int codec_powered;
|
||||
|
||||
/* reference counts of AIF/APLL users */
|
||||
unsigned int apll_enabled;
|
||||
|
||||
struct snd_pcm_substream *master_substream;
|
||||
@@ -136,9 +138,11 @@ struct twl4030_priv {
|
||||
|
||||
unsigned int sysclk;
|
||||
|
||||
/* Headset output state handling */
|
||||
unsigned int hsl_enabled;
|
||||
unsigned int hsr_enabled;
|
||||
/* Output (with associated amp) states */
|
||||
u8 hsl_enabled, hsr_enabled;
|
||||
u8 earpiece_enabled;
|
||||
u8 predrivel_enabled, predriver_enabled;
|
||||
u8 carkitl_enabled, carkitr_enabled;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -174,17 +178,52 @@ static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec,
|
||||
static int twl4030_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
int write_to_reg = 0;
|
||||
|
||||
twl4030_write_reg_cache(codec, reg, value);
|
||||
if (likely(reg < TWL4030_REG_SW_SHADOW))
|
||||
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value,
|
||||
reg);
|
||||
else
|
||||
return 0;
|
||||
if (likely(reg < TWL4030_REG_SW_SHADOW)) {
|
||||
/* Decide if the given register can be written */
|
||||
switch (reg) {
|
||||
case TWL4030_REG_EAR_CTL:
|
||||
if (twl4030->earpiece_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PREDL_CTL:
|
||||
if (twl4030->predrivel_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PREDR_CTL:
|
||||
if (twl4030->predriver_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PRECKL_CTL:
|
||||
if (twl4030->carkitl_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PRECKR_CTL:
|
||||
if (twl4030->carkitr_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_HS_GAIN_SET:
|
||||
if (twl4030->hsl_enabled || twl4030->hsr_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
default:
|
||||
/* All other register can be written */
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
}
|
||||
if (write_to_reg)
|
||||
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
|
||||
value, reg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
int mode;
|
||||
|
||||
if (enable == twl4030->codec_powered)
|
||||
@@ -222,28 +261,28 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
|
||||
|
||||
static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
int status;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
int status = -1;
|
||||
|
||||
if (enable == twl4030->apll_enabled)
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
/* Enable PLL */
|
||||
status = twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL);
|
||||
else
|
||||
/* Disable PLL */
|
||||
status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL);
|
||||
if (enable) {
|
||||
twl4030->apll_enabled++;
|
||||
if (twl4030->apll_enabled == 1)
|
||||
status = twl4030_codec_enable_resource(
|
||||
TWL4030_CODEC_RES_APLL);
|
||||
} else {
|
||||
twl4030->apll_enabled--;
|
||||
if (!twl4030->apll_enabled)
|
||||
status = twl4030_codec_disable_resource(
|
||||
TWL4030_CODEC_RES_APLL);
|
||||
}
|
||||
|
||||
if (status >= 0)
|
||||
twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
|
||||
|
||||
twl4030->apll_enabled = enable;
|
||||
}
|
||||
|
||||
static void twl4030_power_up(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 anamicl, regmisc1, byte;
|
||||
int i = 0;
|
||||
|
||||
@@ -526,26 +565,26 @@ static int micpath_event(struct snd_soc_dapm_widget *w,
|
||||
* Output PGA builder:
|
||||
* Handle the muting and unmuting of the given output (turning off the
|
||||
* amplifier associated with the output pin)
|
||||
* On mute bypass the reg_cache and mute the volume
|
||||
* On unmute: restore the register content
|
||||
* On mute bypass the reg_cache and write 0 to the register
|
||||
* On unmute: restore the register content from the reg_cache
|
||||
* Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R
|
||||
*/
|
||||
#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \
|
||||
static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
|
||||
struct snd_kcontrol *kcontrol, int event) \
|
||||
{ \
|
||||
u8 reg_val; \
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \
|
||||
\
|
||||
switch (event) { \
|
||||
case SND_SOC_DAPM_POST_PMU: \
|
||||
twl4030->pin_name##_enabled = 1; \
|
||||
twl4030_write(w->codec, reg, \
|
||||
twl4030_read_reg_cache(w->codec, reg)); \
|
||||
break; \
|
||||
case SND_SOC_DAPM_POST_PMD: \
|
||||
reg_val = twl4030_read_reg_cache(w->codec, reg); \
|
||||
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \
|
||||
reg_val & (~mask), \
|
||||
reg); \
|
||||
twl4030->pin_name##_enabled = 0; \
|
||||
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \
|
||||
0, reg); \
|
||||
break; \
|
||||
} \
|
||||
return 0; \
|
||||
@@ -636,13 +675,38 @@ static int apll_event(struct snd_soc_dapm_widget *w,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aif_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
u8 audio_if;
|
||||
|
||||
audio_if = twl4030_read_reg_cache(w->codec, TWL4030_REG_AUDIO_IF);
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
/* Enable AIF */
|
||||
/* enable the PLL before we use it to clock the DAI */
|
||||
twl4030_apll_enable(w->codec, 1);
|
||||
|
||||
twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
|
||||
audio_if | TWL4030_AIF_EN);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
/* disable the DAI before we stop it's source PLL */
|
||||
twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
|
||||
audio_if & ~TWL4030_AIF_EN);
|
||||
twl4030_apll_enable(w->codec, 0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
||||
{
|
||||
struct snd_soc_device *socdev = codec->socdev;
|
||||
struct twl4030_setup_data *setup = socdev->codec_data;
|
||||
|
||||
unsigned char hs_gain, hs_pop;
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
/* Base values for ramp delay calculation: 2^19 - 2^26 */
|
||||
unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
|
||||
8388608, 16777216, 33554432, 67108864};
|
||||
@@ -665,7 +729,10 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
||||
/* Headset ramp-up according to the TRM */
|
||||
hs_pop |= TWL4030_VMID_EN;
|
||||
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
|
||||
twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
|
||||
/* Actually write to the register */
|
||||
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
|
||||
hs_gain,
|
||||
TWL4030_REG_HS_GAIN_SET);
|
||||
hs_pop |= TWL4030_RAMP_EN;
|
||||
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
|
||||
/* Wait ramp delay time + 1, so the VMID can settle */
|
||||
@@ -702,7 +769,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
||||
static int headsetlpga_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = w->codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
@@ -726,7 +793,7 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,
|
||||
static int headsetrpga_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = w->codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
@@ -918,7 +985,7 @@ 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);
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
unsigned short val;
|
||||
unsigned short mask, bitmask;
|
||||
@@ -1036,6 +1103,16 @@ static const struct soc_enum twl4030_vibradir_enum =
|
||||
ARRAY_SIZE(twl4030_vibradir_texts),
|
||||
twl4030_vibradir_texts);
|
||||
|
||||
/* Digimic Left and right swapping */
|
||||
static const char *twl4030_digimicswap_texts[] = {
|
||||
"Not swapped", "Swapped",
|
||||
};
|
||||
|
||||
static const struct soc_enum twl4030_digimicswap_enum =
|
||||
SOC_ENUM_SINGLE(TWL4030_REG_MISC_SET_1, 0,
|
||||
ARRAY_SIZE(twl4030_digimicswap_texts),
|
||||
twl4030_digimicswap_texts);
|
||||
|
||||
static const struct snd_kcontrol_new twl4030_snd_controls[] = {
|
||||
/* Codec operation mode control */
|
||||
SOC_ENUM_EXT("Codec Operation Mode", twl4030_op_modes_enum,
|
||||
@@ -1112,6 +1189,8 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
|
||||
|
||||
SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum),
|
||||
SOC_ENUM("Vibra H-bridge direction", twl4030_vibradir_enum),
|
||||
|
||||
SOC_ENUM("Digimic LR Swap", twl4030_digimicswap_enum),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
||||
@@ -1128,8 +1207,6 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("DIGIMIC1"),
|
||||
|
||||
/* Outputs */
|
||||
SND_SOC_DAPM_OUTPUT("OUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("OUTR"),
|
||||
SND_SOC_DAPM_OUTPUT("EARPIECE"),
|
||||
SND_SOC_DAPM_OUTPUT("PREDRIVEL"),
|
||||
SND_SOC_DAPM_OUTPUT("PREDRIVER"),
|
||||
@@ -1141,6 +1218,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_OUTPUT("HFR"),
|
||||
SND_SOC_DAPM_OUTPUT("VIBRA"),
|
||||
|
||||
/* AIF and APLL clocks for running DAIs (including loopback) */
|
||||
SND_SOC_DAPM_OUTPUT("Virtual HiFi OUT"),
|
||||
SND_SOC_DAPM_INPUT("Virtual HiFi IN"),
|
||||
SND_SOC_DAPM_OUTPUT("Virtual Voice OUT"),
|
||||
|
||||
/* DACs */
|
||||
SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback",
|
||||
SND_SOC_NOPM, 0, 0),
|
||||
@@ -1204,7 +1286,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event,
|
||||
SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("AIF Enable", TWL4030_REG_AUDIO_IF, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("AIF Enable", SND_SOC_NOPM, 0, 0, aif_event,
|
||||
SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
/* Output MIXER controls */
|
||||
/* Earpiece */
|
||||
@@ -1334,10 +1417,6 @@ static const struct snd_soc_dapm_route intercon[] = {
|
||||
{"Digital Voice Playback Mixer", NULL, "DAC Voice"},
|
||||
|
||||
/* Supply for the digital part (APLL) */
|
||||
{"Digital R1 Playback Mixer", NULL, "APLL Enable"},
|
||||
{"Digital L1 Playback Mixer", NULL, "APLL Enable"},
|
||||
{"Digital R2 Playback Mixer", NULL, "APLL Enable"},
|
||||
{"Digital L2 Playback Mixer", NULL, "APLL Enable"},
|
||||
{"Digital Voice Playback Mixer", NULL, "APLL Enable"},
|
||||
|
||||
{"Digital R1 Playback Mixer", NULL, "AIF Enable"},
|
||||
@@ -1411,8 +1490,14 @@ static const struct snd_soc_dapm_route intercon[] = {
|
||||
{"Vibra Mux", "AudioR2", "DAC Right2"},
|
||||
|
||||
/* outputs */
|
||||
{"OUTL", NULL, "Analog L2 Playback Mixer"},
|
||||
{"OUTR", NULL, "Analog R2 Playback Mixer"},
|
||||
/* Must be always connected (for AIF and APLL) */
|
||||
{"Virtual HiFi OUT", NULL, "Digital L1 Playback Mixer"},
|
||||
{"Virtual HiFi OUT", NULL, "Digital R1 Playback Mixer"},
|
||||
{"Virtual HiFi OUT", NULL, "Digital L2 Playback Mixer"},
|
||||
{"Virtual HiFi OUT", NULL, "Digital R2 Playback Mixer"},
|
||||
/* Must be always connected (for APLL) */
|
||||
{"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"},
|
||||
/* Physical outputs */
|
||||
{"EARPIECE", NULL, "Earpiece PGA"},
|
||||
{"PREDRIVEL", NULL, "PredriveL PGA"},
|
||||
{"PREDRIVER", NULL, "PredriveR PGA"},
|
||||
@@ -1426,6 +1511,12 @@ static const struct snd_soc_dapm_route intercon[] = {
|
||||
{"VIBRA", NULL, "Vibra Route"},
|
||||
|
||||
/* Capture path */
|
||||
/* Must be always connected (for AIF and APLL) */
|
||||
{"ADC Virtual Left1", NULL, "Virtual HiFi IN"},
|
||||
{"ADC Virtual Right1", NULL, "Virtual HiFi IN"},
|
||||
{"ADC Virtual Left2", NULL, "Virtual HiFi IN"},
|
||||
{"ADC Virtual Right2", NULL, "Virtual HiFi IN"},
|
||||
/* Physical inputs */
|
||||
{"Analog Left", "Main Mic Capture Switch", "MAINMIC"},
|
||||
{"Analog Left", "Headset Mic Capture Switch", "HSMIC"},
|
||||
{"Analog Left", "AUXL Capture Switch", "AUXL"},
|
||||
@@ -1458,11 +1549,6 @@ static const struct snd_soc_dapm_route intercon[] = {
|
||||
{"ADC Virtual Left2", NULL, "TX2 Capture Route"},
|
||||
{"ADC Virtual Right2", NULL, "TX2 Capture Route"},
|
||||
|
||||
{"ADC Virtual Left1", NULL, "APLL Enable"},
|
||||
{"ADC Virtual Right1", NULL, "APLL Enable"},
|
||||
{"ADC Virtual Left2", NULL, "APLL Enable"},
|
||||
{"ADC Virtual Right2", NULL, "APLL Enable"},
|
||||
|
||||
{"ADC Virtual Left1", NULL, "AIF Enable"},
|
||||
{"ADC Virtual Right1", NULL, "AIF Enable"},
|
||||
{"ADC Virtual Left2", NULL, "AIF Enable"},
|
||||
@@ -1588,7 +1674,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
|
||||
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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (twl4030->master_substream) {
|
||||
twl4030->slave_substream = substream;
|
||||
@@ -1619,7 +1705,7 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream,
|
||||
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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (twl4030->master_substream == substream)
|
||||
twl4030->master_substream = twl4030->slave_substream;
|
||||
@@ -1645,7 +1731,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
|
||||
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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 mode, old_mode, format, old_format;
|
||||
|
||||
/* If the substream has 4 channel, do the necessary setup */
|
||||
@@ -1765,7 +1851,7 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case 19200000:
|
||||
@@ -1880,7 +1966,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
|
||||
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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 mode;
|
||||
|
||||
/* If the system master clock is not 26MHz, the voice PCM interface is
|
||||
@@ -1962,7 +2048,7 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (freq != 26000000) {
|
||||
dev_err(codec->dev, "Unsupported APLL mclk: %u, the Voice"
|
||||
@@ -2108,7 +2194,6 @@ static int twl4030_soc_resume(struct platform_device *pdev)
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
twl4030_set_bias_level(codec, codec->suspend_bias_level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2125,7 +2210,7 @@ static int twl4030_soc_probe(struct platform_device *pdev)
|
||||
BUG_ON(!twl4030_codec);
|
||||
|
||||
codec = twl4030_codec;
|
||||
twl4030 = codec->private_data;
|
||||
twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
socdev->card->codec = codec;
|
||||
|
||||
/* Configuration for headset ramp delay from setup data */
|
||||
@@ -2188,7 +2273,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
codec = &twl4030->codec;
|
||||
codec->private_data = twl4030;
|
||||
snd_soc_codec_set_drvdata(codec, twl4030);
|
||||
codec->dev = &pdev->dev;
|
||||
twl4030_dai[0].dev = &pdev->dev;
|
||||
twl4030_dai[1].dev = &pdev->dev;
|
||||
|
新增問題並參考
封鎖使用者