提交 38f7d75e 编写于 作者: M Mark Brown

Merge remote-tracking branch 'asoc/topic/dapm' into asoc-core

...@@ -70,121 +70,144 @@ struct device; ...@@ -70,121 +70,144 @@ struct device;
.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD} .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
#define SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) \
.reg = wreg, .mask = 1, .shift = wshift, \
.on_val = winvert ? 0 : 1, .off_val = winvert ? 1 : 0
/* path domain */ /* path domain */
#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\ #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
wcontrols, wncontrols) \ wcontrols, wncontrols) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_pga, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\ #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
wcontrols, wncontrols) \ wcontrols, wncontrols) \
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_out_drv, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \ #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
wcontrols, wncontrols)\ wcontrols, wncontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_mixer, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \ #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
wcontrols, wncontrols)\ wcontrols, wncontrols)\
{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.num_kcontrols = wncontrols} .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \ #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_micbias, .name = wname, \
.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = NULL, .num_kcontrols = 0}
#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \ #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_switch, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \ #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} .kcontrol_news = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \ #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_virt_mux, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \ { .id = snd_soc_dapm_value_mux, .name = wname, \
.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.num_kcontrols = 1} .kcontrol_news = wcontrols, .num_kcontrols = 1}
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
wcontrols) \ wcontrols) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_pga, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
#define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \ #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
wcontrols)\ wcontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_mixer, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
#define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \ #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
wcontrols)\ wcontrols)\
{ .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \ { .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.num_kcontrols = ARRAY_SIZE(wcontrols)} .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
/* path domain with event - event handler must return 0 for success */ /* path domain with event - event handler must return 0 for success */
#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \ #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \ wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_pga, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \ #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \ wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_out_drv, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \ #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \ wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_mixer, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \ #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
wcontrols, wncontrols, wevent, wflags) \ wcontrols, wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_mixer, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, \
.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags} .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \ #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_switch, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_mux, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_virt_mux, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
/* additional sequencing control within an event type */ /* additional sequencing control within an event type */
#define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \ #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_pga, .name = wname, \
.invert = winvert, .event = wevent, .event_flags = wflags, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event = wevent, .event_flags = wflags, \
.subseq = wsubseq} .subseq = wsubseq}
#define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \ #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
wflags) \ wflags) \
{ .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \ { .id = snd_soc_dapm_supply, .name = wname, \
.shift = wshift, .invert = winvert, .event = wevent, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event_flags = wflags, .subseq = wsubseq} .event = wevent, .event_flags = wflags, .subseq = wsubseq}
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_pga, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \ #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_mixer, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \ #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
wcontrols, wevent, wflags) \ wcontrols, wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \ { .id = snd_soc_dapm_mixer, .name = wname, \
.invert = winvert, .kcontrol_news = wcontrols, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags} .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
.event = wevent, .event_flags = wflags}
/* events that are pre and post DAPM */ /* events that are pre and post DAPM */
#define SND_SOC_DAPM_PRE(wname, wevent) \ #define SND_SOC_DAPM_PRE(wname, wevent) \
...@@ -199,35 +222,36 @@ struct device; ...@@ -199,35 +222,36 @@ struct device;
/* stream domain */ /* stream domain */
#define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \ #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
.reg = wreg, .shift = wshift, .invert = winvert } SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \ #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \ { .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
.reg = wreg, .shift = wshift, .invert = winvert, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event = wevent, .event_flags = wflags } .event = wevent, .event_flags = wflags }
#define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \ #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
.reg = wreg, .shift = wshift, .invert = winvert } SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \ #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \ { .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
.reg = wreg, .shift = wshift, .invert = winvert, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event = wevent, .event_flags = wflags } .event = wevent, .event_flags = wflags }
#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \ #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
.shift = wshift, .invert = winvert} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
#define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \ #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \ { .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
.shift = wshift, .invert = winvert, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \ #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
.shift = wshift, .invert = winvert} SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
#define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \ #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
wevent, wflags) \ wevent, wflags) \
{ .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \ { .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
.shift = wshift, .invert = winvert, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event = wevent, .event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \ #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
{ .id = snd_soc_dapm_clock_supply, .name = wname, \ { .id = snd_soc_dapm_clock_supply, .name = wname, \
...@@ -241,14 +265,14 @@ struct device; ...@@ -241,14 +265,14 @@ struct device;
.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \ .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD} .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
#define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \ #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
{ .id = snd_soc_dapm_supply, .name = wname, .reg = wreg, \ { .id = snd_soc_dapm_supply, .name = wname, \
.shift = wshift, .invert = winvert, .event = wevent, \ SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event_flags = wflags} .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags) \ #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags) \
{ .id = snd_soc_dapm_regulator_supply, .name = wname, \ { .id = snd_soc_dapm_regulator_supply, .name = wname, \
.reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \ .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
.invert = wflags} .on_val = wflags}
/* dapm kcontrol types */ /* dapm kcontrol types */
...@@ -256,14 +280,26 @@ struct device; ...@@ -256,14 +280,26 @@ struct device;
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
#define SOC_DAPM_SINGLE_AUTODISABLE(xname, reg, shift, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \ .tlv.p = (tlv_array), \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
#define SOC_DAPM_SINGLE_TLV_AUTODISABLE(xname, reg, shift, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
#define SOC_DAPM_ENUM(xname, xenum) \ #define SOC_DAPM_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_enum_double, \ .info = snd_soc_info_enum_double, \
...@@ -333,6 +369,7 @@ struct snd_soc_dapm_route; ...@@ -333,6 +369,7 @@ struct snd_soc_dapm_route;
struct snd_soc_dapm_context; struct snd_soc_dapm_context;
struct regulator; struct regulator;
struct snd_soc_dapm_widget_list; struct snd_soc_dapm_widget_list;
struct snd_soc_dapm_update;
int dapm_reg_event(struct snd_soc_dapm_widget *w, int dapm_reg_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event); struct snd_kcontrol *kcontrol, int event);
...@@ -391,10 +428,12 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, ...@@ -391,10 +428,12 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
void snd_soc_dapm_shutdown(struct snd_soc_card *card); void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* external DAPM widget events */ /* external DAPM widget events */
int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
struct snd_kcontrol *kcontrol, int connect); struct snd_kcontrol *kcontrol, int connect,
int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, struct snd_soc_dapm_update *update);
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e); int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
struct snd_soc_dapm_update *update);
/* dapm sys fs - used by the core */ /* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev); int snd_soc_dapm_sys_add(struct device *dev);
...@@ -424,6 +463,8 @@ void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm); ...@@ -424,6 +463,8 @@ void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
struct snd_soc_dapm_widget_list **list); struct snd_soc_dapm_widget_list **list);
struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol);
/* dapm widget types */ /* dapm widget types */
enum snd_soc_dapm_type { enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */ snd_soc_dapm_input = 0, /* input pin */
...@@ -455,6 +496,7 @@ enum snd_soc_dapm_type { ...@@ -455,6 +496,7 @@ enum snd_soc_dapm_type {
snd_soc_dapm_dai_in, /* link to DAI structure */ snd_soc_dapm_dai_in, /* link to DAI structure */
snd_soc_dapm_dai_out, snd_soc_dapm_dai_out,
snd_soc_dapm_dai_link, /* link between two DAI structures */ snd_soc_dapm_dai_link, /* link between two DAI structures */
snd_soc_dapm_kcontrol, /* Auto-disabled kcontrol */
}; };
enum snd_soc_dapm_subclass { enum snd_soc_dapm_subclass {
...@@ -485,7 +527,6 @@ struct snd_soc_dapm_path { ...@@ -485,7 +527,6 @@ struct snd_soc_dapm_path {
/* source (input) and sink (output) widgets */ /* source (input) and sink (output) widgets */
struct snd_soc_dapm_widget *source; struct snd_soc_dapm_widget *source;
struct snd_soc_dapm_widget *sink; struct snd_soc_dapm_widget *sink;
struct snd_kcontrol *kcontrol;
/* status */ /* status */
u32 connect:1; /* source and sink widgets are connected */ u32 connect:1; /* source and sink widgets are connected */
...@@ -498,6 +539,7 @@ struct snd_soc_dapm_path { ...@@ -498,6 +539,7 @@ struct snd_soc_dapm_path {
struct list_head list_source; struct list_head list_source;
struct list_head list_sink; struct list_head list_sink;
struct list_head list_kcontrol;
struct list_head list; struct list_head list;
}; };
...@@ -518,12 +560,10 @@ struct snd_soc_dapm_widget { ...@@ -518,12 +560,10 @@ struct snd_soc_dapm_widget {
/* dapm control */ /* dapm control */
int reg; /* negative reg = no direct dapm */ int reg; /* negative reg = no direct dapm */
unsigned char shift; /* bits to shift */ unsigned char shift; /* bits to shift */
unsigned int value; /* widget current value */
unsigned int mask; /* non-shifted mask */ unsigned int mask; /* non-shifted mask */
unsigned int on_val; /* on state value */ unsigned int on_val; /* on state value */
unsigned int off_val; /* off state value */ unsigned int off_val; /* off state value */
unsigned char power:1; /* block power status */ unsigned char power:1; /* block power status */
unsigned char invert:1; /* invert the power bit */
unsigned char active:1; /* active stream on DAC, ADC's */ unsigned char active:1; /* active stream on DAC, ADC's */
unsigned char connected:1; /* connected codec pin */ unsigned char connected:1; /* connected codec pin */
unsigned char new:1; /* cnew complete */ unsigned char new:1; /* cnew complete */
...@@ -559,7 +599,6 @@ struct snd_soc_dapm_widget { ...@@ -559,7 +599,6 @@ struct snd_soc_dapm_widget {
}; };
struct snd_soc_dapm_update { struct snd_soc_dapm_update {
struct snd_soc_dapm_widget *widget;
struct snd_kcontrol *kcontrol; struct snd_kcontrol *kcontrol;
int reg; int reg;
int mask; int mask;
...@@ -573,8 +612,6 @@ struct snd_soc_dapm_context { ...@@ -573,8 +612,6 @@ struct snd_soc_dapm_context {
struct delayed_work delayed_work; struct delayed_work delayed_work;
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */ unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
struct snd_soc_dapm_update *update;
void (*seq_notifier)(struct snd_soc_dapm_context *, void (*seq_notifier)(struct snd_soc_dapm_context *,
enum snd_soc_dapm_type, int); enum snd_soc_dapm_type, int);
......
...@@ -133,6 +133,6 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream, ...@@ -133,6 +133,6 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
/* internal use only */ /* internal use only */
int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute); int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd); int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *); int soc_dpcm_runtime_update(struct snd_soc_card *);
#endif #endif
...@@ -30,13 +30,13 @@ ...@@ -30,13 +30,13 @@
/* /*
* Convenience kcontrol builders * Convenience kcontrol builders
*/ */
#define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert) \ #define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert, xautodisable) \
((unsigned long)&(struct soc_mixer_control) \ ((unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .rreg = xreg, .shift = shift_left, \ {.reg = xreg, .rreg = xreg, .shift = shift_left, \
.rshift = shift_right, .max = xmax, .platform_max = xmax, \ .rshift = shift_right, .max = xmax, .platform_max = xmax, \
.invert = xinvert}) .invert = xinvert, .autodisable = xautodisable})
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert) SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
((unsigned long)&(struct soc_mixer_control) \ ((unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert})
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw, \ .put = snd_soc_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
#define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \ #define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \ .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
.tlv.p = (tlv_array), \ .tlv.p = (tlv_array), \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw, \ .put = snd_soc_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
#define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \ #define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
.put = snd_soc_put_volsw, \ .put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
max, invert) } max, invert, 0) }
#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
...@@ -119,7 +119,7 @@ ...@@ -119,7 +119,7 @@
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
.put = snd_soc_put_volsw, \ .put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
max, invert) } max, invert, 0) }
#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
...@@ -190,14 +190,14 @@ ...@@ -190,14 +190,14 @@
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \ .get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
#define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\ #define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\
xhandler_get, xhandler_put) \ xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \ .get = xhandler_get, .put = xhandler_put, \
.private_value = \ .private_value = \
SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) } SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert, 0) }
#define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
xhandler_get, xhandler_put, tlv_array) \ xhandler_get, xhandler_put, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
...@@ -206,7 +206,7 @@ ...@@ -206,7 +206,7 @@
.tlv.p = (tlv_array), \ .tlv.p = (tlv_array), \
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \ .get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
#define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\ #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\
xhandler_get, xhandler_put, tlv_array) \ xhandler_get, xhandler_put, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
...@@ -216,7 +216,7 @@ ...@@ -216,7 +216,7 @@
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \ .get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \ .private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \
xmax, xinvert) } xmax, xinvert, 0) }
#define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\
xhandler_get, xhandler_put, tlv_array) \ xhandler_get, xhandler_put, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
...@@ -1038,6 +1038,7 @@ struct snd_soc_card { ...@@ -1038,6 +1038,7 @@ struct snd_soc_card {
/* Generic DAPM context for the card */ /* Generic DAPM context for the card */
struct snd_soc_dapm_context dapm; struct snd_soc_dapm_context dapm;
struct snd_soc_dapm_stats dapm_stats; struct snd_soc_dapm_stats dapm_stats;
struct snd_soc_dapm_update *update;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_card_root; struct dentry *debugfs_card_root;
...@@ -1083,7 +1084,9 @@ struct snd_soc_pcm_runtime { ...@@ -1083,7 +1084,9 @@ struct snd_soc_pcm_runtime {
/* mixer control */ /* mixer control */
struct soc_mixer_control { struct soc_mixer_control {
int min, max, platform_max; int min, max, platform_max;
unsigned int reg, rreg, shift, rshift, invert; unsigned int reg, rreg, shift, rshift;
unsigned int invert:1;
unsigned int autodisable:1;
}; };
struct soc_bytes { struct soc_bytes {
......
...@@ -138,8 +138,7 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { ...@@ -138,8 +138,7 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct soc_mixer_control *mc = struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg; unsigned int reg = mc->reg;
...@@ -147,10 +146,9 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, ...@@ -147,10 +146,9 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
int max = mc->max; int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1; unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert; unsigned int invert = mc->invert;
unsigned short val, val_mask; unsigned short val;
int ret; struct snd_soc_dapm_update update;
struct snd_soc_dapm_path *path; int connect, change;
int found = 0;
val = (ucontrol->value.integer.value[0] & mask); val = (ucontrol->value.integer.value[0] & mask);
...@@ -158,42 +156,26 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, ...@@ -158,42 +156,26 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
if (val) if (val)
val = mask; val = mask;
connect = !!val;
if (invert) if (invert)
val = mask - val; val = mask - val;
val_mask = mask << shift;
val = val << shift;
mutex_lock(&widget->codec->mutex);
if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) { mask <<= shift;
/* find dapm widget path assoc with kcontrol */ val <<= shift;
list_for_each_entry(path, &widget->dapm->card->paths, list) {
if (path->kcontrol != kcontrol)
continue;
/* found, now check type */ change = snd_soc_test_bits(codec, val, mask, reg);
found = 1; if (change) {
if (val) update.kcontrol = kcontrol;
/* new connection */ update.reg = reg;
path->connect = invert ? 0 : 1; update.mask = mask;
else update.val = val;
/* old connection must be powered down */
path->connect = invert ? 1 : 0;
dapm_mark_dirty(path->source, "tlv320aic3x source"); snd_soc_dapm_mixer_update_power(&codec->dapm, kcontrol, connect,
dapm_mark_dirty(path->sink, "tlv320aic3x sink"); &update);
break;
}
} }
mutex_unlock(&widget->codec->mutex); return change;
if (found)
snd_soc_dapm_sync(widget->dapm);
ret = snd_soc_update_bits_locked(widget->codec, reg, val_mask, val);
return ret;
} }
/* /*
......
...@@ -437,9 +437,7 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data) ...@@ -437,9 +437,7 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol, static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val; unsigned int val;
......
...@@ -364,9 +364,7 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm, ...@@ -364,9 +364,7 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
u16 reg; u16 reg;
int ret; int ret;
......
...@@ -1437,9 +1437,7 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, ...@@ -1437,9 +1437,7 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *w = wlist->widgets[0];
struct snd_soc_codec *codec = w->codec;
int ret; int ret;
ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
......
...@@ -549,12 +549,9 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source, ...@@ -549,12 +549,9 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source,
static int wm8995_put_class_w(struct snd_kcontrol *kcontrol, static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *w = wlist->widgets[0];
struct snd_soc_codec *codec;
int ret; int ret;
codec = w->codec;
ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
wm8995_update_class_w(codec); wm8995_update_class_w(codec);
return ret; return ret;
......
...@@ -699,9 +699,7 @@ EXPORT_SYMBOL_GPL(wm_hubs_update_class_w); ...@@ -699,9 +699,7 @@ EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
static int class_w_put_volsw(struct snd_kcontrol *kcontrol, static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
int ret; int ret;
ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol); ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
...@@ -721,9 +719,7 @@ static int class_w_put_volsw(struct snd_kcontrol *kcontrol, ...@@ -721,9 +719,7 @@ static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
static int class_w_put_double(struct snd_kcontrol *kcontrol, static int class_w_put_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
int ret; int ret;
ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
......
...@@ -47,6 +47,15 @@ ...@@ -47,6 +47,15 @@
#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++; #define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
const char *control,
int (*connected)(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink));
static struct snd_soc_dapm_widget *
snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget);
/* dapm power sequences - make this per codec in the future */ /* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = { static int dapm_up_seq[] = {
[snd_soc_dapm_pre] = 0, [snd_soc_dapm_pre] = 0,
...@@ -73,16 +82,18 @@ static int dapm_up_seq[] = { ...@@ -73,16 +82,18 @@ static int dapm_up_seq[] = {
[snd_soc_dapm_hp] = 10, [snd_soc_dapm_hp] = 10,
[snd_soc_dapm_spk] = 10, [snd_soc_dapm_spk] = 10,
[snd_soc_dapm_line] = 10, [snd_soc_dapm_line] = 10,
[snd_soc_dapm_post] = 11, [snd_soc_dapm_kcontrol] = 11,
[snd_soc_dapm_post] = 12,
}; };
static int dapm_down_seq[] = { static int dapm_down_seq[] = {
[snd_soc_dapm_pre] = 0, [snd_soc_dapm_pre] = 0,
[snd_soc_dapm_adc] = 1, [snd_soc_dapm_kcontrol] = 1,
[snd_soc_dapm_hp] = 2, [snd_soc_dapm_adc] = 2,
[snd_soc_dapm_spk] = 2, [snd_soc_dapm_hp] = 3,
[snd_soc_dapm_line] = 2, [snd_soc_dapm_spk] = 3,
[snd_soc_dapm_out_drv] = 2, [snd_soc_dapm_line] = 3,
[snd_soc_dapm_out_drv] = 3,
[snd_soc_dapm_pga] = 4, [snd_soc_dapm_pga] = 4,
[snd_soc_dapm_switch] = 5, [snd_soc_dapm_switch] = 5,
[snd_soc_dapm_mixer_named_ctl] = 5, [snd_soc_dapm_mixer_named_ctl] = 5,
...@@ -174,6 +185,176 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( ...@@ -174,6 +185,176 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
} }
struct dapm_kcontrol_data {
unsigned int value;
struct snd_soc_dapm_widget *widget;
struct list_head paths;
struct snd_soc_dapm_widget_list *wlist;
};
static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol)
{
struct dapm_kcontrol_data *data;
struct soc_mixer_control *mc;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(widget->dapm->dev,
"ASoC: can't allocate kcontrol data for %s\n",
widget->name);
return -ENOMEM;
}
INIT_LIST_HEAD(&data->paths);
switch (widget->id) {
case snd_soc_dapm_switch:
case snd_soc_dapm_mixer:
case snd_soc_dapm_mixer_named_ctl:
mc = (struct soc_mixer_control *)kcontrol->private_value;
if (mc->autodisable) {
struct snd_soc_dapm_widget template;
memset(&template, 0, sizeof(template));
template.reg = mc->reg;
template.mask = (1 << fls(mc->max)) - 1;
template.shift = mc->shift;
if (mc->invert)
template.off_val = mc->max;
else
template.off_val = 0;
template.on_val = template.off_val;
template.id = snd_soc_dapm_kcontrol;
template.name = kcontrol->id.name;
data->widget = snd_soc_dapm_new_control(widget->dapm,
&template);
if (!data->widget) {
kfree(data);
return -ENOMEM;
}
}
break;
default:
break;
}
kcontrol->private_data = data;
return 0;
}
static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
kfree(data->widget);
kfree(data->wlist);
kfree(data);
}
static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
const struct snd_kcontrol *kcontrol)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
return data->wlist;
}
static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget *widget)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget_list *new_wlist;
unsigned int n;
if (data->wlist)
n = data->wlist->num_widgets + 1;
else
n = 1;
new_wlist = krealloc(data->wlist,
sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
if (!new_wlist)
return -ENOMEM;
new_wlist->widgets[n - 1] = widget;
new_wlist->num_widgets = n;
data->wlist = new_wlist;
return 0;
}
static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_path *path)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
list_add_tail(&path->list_kcontrol, &data->paths);
if (data->widget) {
snd_soc_dapm_add_path(data->widget->dapm, data->widget,
path->source, NULL, NULL);
}
}
static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
if (!data->widget)
return true;
return data->widget->power;
}
static struct list_head *dapm_kcontrol_get_path_list(
const struct snd_kcontrol *kcontrol)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
return &data->paths;
}
#define dapm_kcontrol_for_each_path(path, kcontrol) \
list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
list_kcontrol)
static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
return data->value;
}
static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
unsigned int value)
{
struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
if (data->value == value)
return false;
if (data->widget)
data->widget->on_val = value;
data->value = value;
return true;
}
/**
* snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
* @kcontrol: The kcontrol
*/
struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol)
{
return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec);
static void dapm_reset(struct snd_soc_card *card) static void dapm_reset(struct snd_soc_card *card)
{ {
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
...@@ -181,6 +362,7 @@ static void dapm_reset(struct snd_soc_card *card) ...@@ -181,6 +362,7 @@ static void dapm_reset(struct snd_soc_card *card)
memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
list_for_each_entry(w, &card->widgets, list) { list_for_each_entry(w, &card->widgets, list) {
w->new_power = w->power;
w->power_checked = false; w->power_checked = false;
w->inputs = -1; w->inputs = -1;
w->outputs = -1; w->outputs = -1;
...@@ -398,6 +580,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, ...@@ -398,6 +580,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
case snd_soc_dapm_spk: case snd_soc_dapm_spk:
case snd_soc_dapm_line: case snd_soc_dapm_line:
case snd_soc_dapm_dai_link: case snd_soc_dapm_dai_link:
case snd_soc_dapm_kcontrol:
p->connect = 1; p->connect = 1;
break; break;
/* does affect routing - dynamically connected */ /* does affect routing - dynamically connected */
...@@ -477,17 +660,12 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, ...@@ -477,17 +660,12 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
return 0; return 0;
} }
static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
{
kfree(kctl->private_data);
}
/* /*
* Determine if a kcontrol is shared. If it is, look it up. If it isn't, * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
* create it. Either way, add the widget into the control's widget list * create it. Either way, add the widget into the control's widget list
*/ */
static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
int kci, struct snd_soc_dapm_path *path) int kci)
{ {
struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_card *card = dapm->card->snd_card; struct snd_card *card = dapm->card->snd_card;
...@@ -495,9 +673,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, ...@@ -495,9 +673,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
size_t prefix_len; size_t prefix_len;
int shared; int shared;
struct snd_kcontrol *kcontrol; struct snd_kcontrol *kcontrol;
struct snd_soc_dapm_widget_list *wlist;
int wlistentries;
size_t wlistsize;
bool wname_in_long_name, kcname_in_long_name; bool wname_in_long_name, kcname_in_long_name;
char *long_name; char *long_name;
const char *name; const char *name;
...@@ -516,25 +691,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, ...@@ -516,25 +691,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci], shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
&kcontrol); &kcontrol);
if (kcontrol) {
wlist = kcontrol->private_data;
wlistentries = wlist->num_widgets + 1;
} else {
wlist = NULL;
wlistentries = 1;
}
wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
wlistentries * sizeof(struct snd_soc_dapm_widget *);
wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
if (wlist == NULL) {
dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n",
w->name);
return -ENOMEM;
}
wlist->num_widgets = wlistentries;
wlist->widgets[wlistentries - 1] = w;
if (!kcontrol) { if (!kcontrol) {
if (shared) { if (shared) {
wname_in_long_name = false; wname_in_long_name = false;
...@@ -557,7 +713,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, ...@@ -557,7 +713,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
kcname_in_long_name = false; kcname_in_long_name = false;
break; break;
default: default:
kfree(wlist);
return -EINVAL; return -EINVAL;
} }
} }
...@@ -572,10 +727,8 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, ...@@ -572,10 +727,8 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
long_name = kasprintf(GFP_KERNEL, "%s %s", long_name = kasprintf(GFP_KERNEL, "%s %s",
w->name + prefix_len, w->name + prefix_len,
w->kcontrol_news[kci].name); w->kcontrol_news[kci].name);
if (long_name == NULL) { if (long_name == NULL)
kfree(wlist);
return -ENOMEM; return -ENOMEM;
}
name = long_name; name = long_name;
} else if (wname_in_long_name) { } else if (wname_in_long_name) {
...@@ -586,23 +739,33 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, ...@@ -586,23 +739,33 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
name = w->kcontrol_news[kci].name; name = w->kcontrol_news[kci].name;
} }
kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name, kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
prefix); prefix);
kcontrol->private_free = dapm_kcontrol_free;
kfree(long_name); kfree(long_name);
if (!kcontrol)
return -ENOMEM;
kcontrol->private_free = dapm_kcontrol_free;
ret = dapm_kcontrol_data_alloc(w, kcontrol);
if (ret) {
snd_ctl_free_one(kcontrol);
return ret;
}
ret = snd_ctl_add(card, kcontrol); ret = snd_ctl_add(card, kcontrol);
if (ret < 0) { if (ret < 0) {
dev_err(dapm->dev, dev_err(dapm->dev,
"ASoC: failed to add widget %s dapm kcontrol %s: %d\n", "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
w->name, name, ret); w->name, name, ret);
kfree(wlist);
return ret; return ret;
} }
} }
kcontrol->private_data = wlist; ret = dapm_kcontrol_add_widget(kcontrol, w);
if (ret)
return ret;
w->kcontrols[kci] = kcontrol; w->kcontrols[kci] = kcontrol;
path->kcontrol = kcontrol;
return 0; return 0;
} }
...@@ -622,13 +785,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) ...@@ -622,13 +785,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
continue; continue;
if (w->kcontrols[i]) { if (w->kcontrols[i]) {
path->kcontrol = w->kcontrols[i]; dapm_kcontrol_add_path(w->kcontrols[i], path);
continue; continue;
} }
ret = dapm_create_or_share_mixmux_kcontrol(w, i, path); ret = dapm_create_or_share_mixmux_kcontrol(w, i);
if (ret < 0) if (ret < 0)
return ret; return ret;
dapm_kcontrol_add_path(w->kcontrols[i], path);
} }
} }
...@@ -654,15 +819,12 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) ...@@ -654,15 +819,12 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
return -EINVAL; return -EINVAL;
} }
path = list_first_entry(&w->sources, struct snd_soc_dapm_path, ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
list_sink);
ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
if (ret < 0) if (ret < 0)
return ret; return ret;
list_for_each_entry(path, &w->sources, list_sink) list_for_each_entry(path, &w->sources, list_sink)
path->kcontrol = w->kcontrols[0]; dapm_kcontrol_add_path(w->kcontrols[0], path);
return 0; return 0;
} }
...@@ -783,6 +945,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, ...@@ -783,6 +945,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply: case snd_soc_dapm_clock_supply:
case snd_soc_dapm_kcontrol:
return 0; return 0;
default: default:
break; break;
...@@ -878,6 +1041,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, ...@@ -878,6 +1041,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply: case snd_soc_dapm_clock_supply:
case snd_soc_dapm_kcontrol:
return 0; return 0;
default: default:
break; break;
...@@ -1032,7 +1196,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ...@@ -1032,7 +1196,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
int ret; int ret;
if (SND_SOC_DAPM_EVENT_ON(event)) { if (SND_SOC_DAPM_EVENT_ON(event)) {
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, false); ret = regulator_allow_bypass(w->regulator, false);
if (ret != 0) if (ret != 0)
dev_warn(w->dapm->dev, dev_warn(w->dapm->dev,
...@@ -1042,7 +1206,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ...@@ -1042,7 +1206,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
return regulator_enable(w->regulator); return regulator_enable(w->regulator);
} else { } else {
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, true); ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0) if (ret != 0)
dev_warn(w->dapm->dev, dev_warn(w->dapm->dev,
...@@ -1214,10 +1378,9 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, ...@@ -1214,10 +1378,9 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
list_add_tail(&new_widget->power_list, list); list_add_tail(&new_widget->power_list, list);
} }
static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, static void dapm_seq_check_event(struct snd_soc_card *card,
struct snd_soc_dapm_widget *w, int event) struct snd_soc_dapm_widget *w, int event)
{ {
struct snd_soc_card *card = dapm->card;
const char *ev_name; const char *ev_name;
int power, ret; int power, ret;
...@@ -1251,55 +1414,50 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm, ...@@ -1251,55 +1414,50 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
return; return;
} }
if (w->power != power) if (w->new_power != power)
return; return;
if (w->event && (w->event_flags & event)) { if (w->event && (w->event_flags & event)) {
pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n", pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
w->name, ev_name); w->name, ev_name);
trace_snd_soc_dapm_widget_event_start(w, event); trace_snd_soc_dapm_widget_event_start(w, event);
ret = w->event(w, NULL, event); ret = w->event(w, NULL, event);
trace_snd_soc_dapm_widget_event_done(w, event); trace_snd_soc_dapm_widget_event_done(w, event);
if (ret < 0) if (ret < 0)
dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n", dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
ev_name, w->name, ret); ev_name, w->name, ret);
} }
} }
/* Apply the coalesced changes from a DAPM sequence */ /* Apply the coalesced changes from a DAPM sequence */
static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, static void dapm_seq_run_coalesced(struct snd_soc_card *card,
struct list_head *pending) struct list_head *pending)
{ {
struct snd_soc_card *card = dapm->card;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
int reg, power; int reg;
unsigned int value = 0; unsigned int value = 0;
unsigned int mask = 0; unsigned int mask = 0;
unsigned int cur_mask;
reg = list_first_entry(pending, struct snd_soc_dapm_widget, reg = list_first_entry(pending, struct snd_soc_dapm_widget,
power_list)->reg; power_list)->reg;
list_for_each_entry(w, pending, power_list) { list_for_each_entry(w, pending, power_list) {
cur_mask = 1 << w->shift;
BUG_ON(reg != w->reg); BUG_ON(reg != w->reg);
w->power = w->new_power;
if (w->invert) mask |= w->mask << w->shift;
power = !w->power; if (w->power)
value |= w->on_val << w->shift;
else else
power = w->power; value |= w->off_val << w->shift;
mask |= cur_mask;
if (power)
value |= cur_mask;
pop_dbg(dapm->dev, card->pop_time, pop_dbg(w->dapm->dev, card->pop_time,
"pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n", "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
w->name, reg, value, mask); w->name, reg, value, mask);
/* Check for events */ /* Check for events */
dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU); dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD); dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
} }
if (reg >= 0) { if (reg >= 0) {
...@@ -1309,7 +1467,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, ...@@ -1309,7 +1467,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
w = list_first_entry(pending, struct snd_soc_dapm_widget, w = list_first_entry(pending, struct snd_soc_dapm_widget,
power_list); power_list);
pop_dbg(dapm->dev, card->pop_time, pop_dbg(w->dapm->dev, card->pop_time,
"pop test : Applying 0x%x/0x%x to %x in %dms\n", "pop test : Applying 0x%x/0x%x to %x in %dms\n",
value, mask, reg, card->pop_time); value, mask, reg, card->pop_time);
pop_wait(card->pop_time); pop_wait(card->pop_time);
...@@ -1317,8 +1475,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, ...@@ -1317,8 +1475,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
} }
list_for_each_entry(w, pending, power_list) { list_for_each_entry(w, pending, power_list) {
dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU); dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD); dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
} }
} }
...@@ -1330,8 +1488,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, ...@@ -1330,8 +1488,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
* Currently anything that requires more than a single write is not * Currently anything that requires more than a single write is not
* handled. * handled.
*/ */
static void dapm_seq_run(struct snd_soc_dapm_context *dapm, static void dapm_seq_run(struct snd_soc_card *card,
struct list_head *list, int event, bool power_up) struct list_head *list, int event, bool power_up)
{ {
struct snd_soc_dapm_widget *w, *n; struct snd_soc_dapm_widget *w, *n;
LIST_HEAD(pending); LIST_HEAD(pending);
...@@ -1354,7 +1512,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, ...@@ -1354,7 +1512,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
if (sort[w->id] != cur_sort || w->reg != cur_reg || if (sort[w->id] != cur_sort || w->reg != cur_reg ||
w->dapm != cur_dapm || w->subseq != cur_subseq) { w->dapm != cur_dapm || w->subseq != cur_subseq) {
if (!list_empty(&pending)) if (!list_empty(&pending))
dapm_seq_run_coalesced(cur_dapm, &pending); dapm_seq_run_coalesced(card, &pending);
if (cur_dapm && cur_dapm->seq_notifier) { if (cur_dapm && cur_dapm->seq_notifier) {
for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
...@@ -1414,7 +1572,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, ...@@ -1414,7 +1572,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
} }
if (!list_empty(&pending)) if (!list_empty(&pending))
dapm_seq_run_coalesced(cur_dapm, &pending); dapm_seq_run_coalesced(card, &pending);
if (cur_dapm && cur_dapm->seq_notifier) { if (cur_dapm && cur_dapm->seq_notifier) {
for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
...@@ -1424,37 +1582,48 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, ...@@ -1424,37 +1582,48 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
} }
} }
static void dapm_widget_update(struct snd_soc_dapm_context *dapm) static void dapm_widget_update(struct snd_soc_card *card)
{ {
struct snd_soc_dapm_update *update = dapm->update; struct snd_soc_dapm_update *update = card->update;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget_list *wlist;
struct snd_soc_dapm_widget *w = NULL;
unsigned int wi;
int ret; int ret;
if (!update) if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
return; return;
w = update->widget; wlist = dapm_kcontrol_get_wlist(update->kcontrol);
if (w->event && for (wi = 0; wi < wlist->num_widgets; wi++) {
(w->event_flags & SND_SOC_DAPM_PRE_REG)) { w = wlist->widgets[wi];
ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
if (ret != 0) if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n", ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
w->name, ret); if (ret != 0)
dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
w->name, ret);
}
} }
if (!w)
return;
ret = soc_widget_update_bits_locked(w, update->reg, update->mask, ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
update->val); update->val);
if (ret < 0) if (ret < 0)
dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n", dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
w->name, ret); w->name, ret);
if (w->event && for (wi = 0; wi < wlist->num_widgets; wi++) {
(w->event_flags & SND_SOC_DAPM_POST_REG)) { w = wlist->widgets[wi];
ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
if (ret != 0) if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n", ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
w->name, ret); if (ret != 0)
dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
w->name, ret);
}
} }
} }
...@@ -1566,6 +1735,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, ...@@ -1566,6 +1735,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply: case snd_soc_dapm_clock_supply:
case snd_soc_dapm_kcontrol:
/* Supplies can't affect their outputs, only their inputs */ /* Supplies can't affect their outputs, only their inputs */
break; break;
default: default:
...@@ -1582,8 +1752,6 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, ...@@ -1582,8 +1752,6 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
dapm_seq_insert(w, up_list, true); dapm_seq_insert(w, up_list, true);
else else
dapm_seq_insert(w, down_list, false); dapm_seq_insert(w, down_list, false);
w->power = power;
} }
static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
...@@ -1617,9 +1785,8 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, ...@@ -1617,9 +1785,8 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
* o Input pin to Output pin (bypass, sidetone) * o Input pin to Output pin (bypass, sidetone)
* o DAC to ADC (loopback). * o DAC to ADC (loopback).
*/ */
static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) static int dapm_power_widgets(struct snd_soc_card *card, int event)
{ {
struct snd_soc_card *card = dapm->card;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
struct snd_soc_dapm_context *d; struct snd_soc_dapm_context *d;
LIST_HEAD(up_list); LIST_HEAD(up_list);
...@@ -1659,7 +1826,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) ...@@ -1659,7 +1826,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
break; break;
} }
if (w->power) { if (w->new_power) {
d = w->dapm; d = w->dapm;
/* Supplies and micbiases only bring the /* Supplies and micbiases only bring the
...@@ -1701,29 +1868,29 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) ...@@ -1701,29 +1868,29 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
trace_snd_soc_dapm_walk_done(card); trace_snd_soc_dapm_walk_done(card);
/* Run all the bias changes in parallel */ /* Run all the bias changes in parallel */
list_for_each_entry(d, &dapm->card->dapm_list, list) list_for_each_entry(d, &card->dapm_list, list)
async_schedule_domain(dapm_pre_sequence_async, d, async_schedule_domain(dapm_pre_sequence_async, d,
&async_domain); &async_domain);
async_synchronize_full_domain(&async_domain); async_synchronize_full_domain(&async_domain);
list_for_each_entry(w, &down_list, power_list) { list_for_each_entry(w, &down_list, power_list) {
dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD); dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
} }
list_for_each_entry(w, &up_list, power_list) { list_for_each_entry(w, &up_list, power_list) {
dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU); dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
} }
/* Power down widgets first; try to avoid amplifying pops. */ /* Power down widgets first; try to avoid amplifying pops. */
dapm_seq_run(dapm, &down_list, event, false); dapm_seq_run(card, &down_list, event, false);
dapm_widget_update(dapm); dapm_widget_update(card);
/* Now power up. */ /* Now power up. */
dapm_seq_run(dapm, &up_list, event, true); dapm_seq_run(card, &up_list, event, true);
/* Run all the bias changes in parallel */ /* Run all the bias changes in parallel */
list_for_each_entry(d, &dapm->card->dapm_list, list) list_for_each_entry(d, &card->dapm_list, list)
async_schedule_domain(dapm_post_sequence_async, d, async_schedule_domain(dapm_post_sequence_async, d,
&async_domain); &async_domain);
async_synchronize_full_domain(&async_domain); async_synchronize_full_domain(&async_domain);
...@@ -1734,7 +1901,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) ...@@ -1734,7 +1901,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
d->stream_event(d, event); d->stream_event(d, event);
} }
pop_dbg(dapm->dev, card->pop_time, pop_dbg(card->dev, card->pop_time,
"DAPM sequencing finished, waiting %dms\n", card->pop_time); "DAPM sequencing finished, waiting %dms\n", card->pop_time);
pop_wait(card->pop_time); pop_wait(card->pop_time);
...@@ -1769,8 +1936,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file, ...@@ -1769,8 +1936,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
if (w->reg >= 0) if (w->reg >= 0)
ret += snprintf(buf + ret, PAGE_SIZE - ret, ret += snprintf(buf + ret, PAGE_SIZE - ret,
" - R%d(0x%x) bit %d", " - R%d(0x%x) mask 0x%x",
w->reg, w->reg, w->shift); w->reg, w->reg, w->mask << w->shift);
ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
...@@ -1907,22 +2074,14 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) ...@@ -1907,22 +2074,14 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
#endif #endif
/* test and update the power status of a mux widget */ /* test and update the power status of a mux widget */
static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, static int soc_dapm_mux_update_power(struct snd_soc_card *card,
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
{ {
struct snd_soc_dapm_path *path; struct snd_soc_dapm_path *path;
int found = 0; int found = 0;
if (widget->id != snd_soc_dapm_mux &&
widget->id != snd_soc_dapm_virt_mux &&
widget->id != snd_soc_dapm_value_mux)
return -ENODEV;
/* find dapm widget path assoc with kcontrol */ /* find dapm widget path assoc with kcontrol */
list_for_each_entry(path, &widget->dapm->card->paths, list) { dapm_kcontrol_for_each_path(path, kcontrol) {
if (path->kcontrol != kcontrol)
continue;
if (!path->name || !e->texts[mux]) if (!path->name || !e->texts[mux])
continue; continue;
...@@ -1937,73 +2096,68 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, ...@@ -1937,73 +2096,68 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
"mux disconnection"); "mux disconnection");
path->connect = 0; /* old connection must be powered down */ path->connect = 0; /* old connection must be powered down */
} }
dapm_mark_dirty(path->sink, "mux change");
} }
if (found) { if (found)
dapm_mark_dirty(widget, "mux change"); dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
}
return found; return found;
} }
int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
struct snd_soc_dapm_update *update)
{ {
struct snd_soc_card *card = widget->dapm->card; struct snd_soc_card *card = dapm->card;
int ret; int ret;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e); card->update = update;
ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
card->update = NULL;
mutex_unlock(&card->dapm_mutex); mutex_unlock(&card->dapm_mutex);
if (ret > 0) if (ret > 0)
soc_dpcm_runtime_update(widget); soc_dpcm_runtime_update(card);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
/* test and update the power status of a mixer or switch widget */ /* test and update the power status of a mixer or switch widget */
static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
struct snd_kcontrol *kcontrol, int connect) struct snd_kcontrol *kcontrol, int connect)
{ {
struct snd_soc_dapm_path *path; struct snd_soc_dapm_path *path;
int found = 0; int found = 0;
if (widget->id != snd_soc_dapm_mixer &&
widget->id != snd_soc_dapm_mixer_named_ctl &&
widget->id != snd_soc_dapm_switch)
return -ENODEV;
/* find dapm widget path assoc with kcontrol */ /* find dapm widget path assoc with kcontrol */
list_for_each_entry(path, &widget->dapm->card->paths, list) { dapm_kcontrol_for_each_path(path, kcontrol) {
if (path->kcontrol != kcontrol)
continue;
/* found, now check type */
found = 1; found = 1;
path->connect = connect; path->connect = connect;
dapm_mark_dirty(path->source, "mixer connection"); dapm_mark_dirty(path->source, "mixer connection");
dapm_mark_dirty(path->sink, "mixer update");
} }
if (found) { if (found)
dapm_mark_dirty(widget, "mixer update"); dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
}
return found; return found;
} }
int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
struct snd_kcontrol *kcontrol, int connect) struct snd_kcontrol *kcontrol, int connect,
struct snd_soc_dapm_update *update)
{ {
struct snd_soc_card *card = widget->dapm->card; struct snd_soc_card *card = dapm->card;
int ret; int ret;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
ret = soc_dapm_mixer_update_power(widget, kcontrol, connect); card->update = update;
ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
card->update = NULL;
mutex_unlock(&card->dapm_mutex); mutex_unlock(&card->dapm_mutex);
if (ret > 0) if (ret > 0)
soc_dpcm_runtime_update(widget); soc_dpcm_runtime_update(card);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
...@@ -2082,6 +2236,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) ...@@ -2082,6 +2236,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path)
{ {
list_del(&path->list_sink); list_del(&path->list_sink);
list_del(&path->list_source); list_del(&path->list_source);
list_del(&path->list_kcontrol);
list_del(&path->list); list_del(&path->list);
kfree(path); kfree(path);
} }
...@@ -2176,70 +2331,20 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) ...@@ -2176,70 +2331,20 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
return 0; return 0;
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
mutex_unlock(&dapm->card->dapm_mutex); mutex_unlock(&dapm->card->dapm_mutex);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route) struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
const char *control,
int (*connected)(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink))
{ {
struct snd_soc_dapm_path *path; struct snd_soc_dapm_path *path;
struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; int ret;
struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
const char *sink;
const char *control = route->control;
const char *source;
char prefixed_sink[80];
char prefixed_source[80];
int ret = 0;
if (dapm->codec && dapm->codec->name_prefix) {
snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
dapm->codec->name_prefix, route->sink);
sink = prefixed_sink;
snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
dapm->codec->name_prefix, route->source);
source = prefixed_source;
} else {
sink = route->sink;
source = route->source;
}
/*
* find src and dest widgets over all widgets but favor a widget from
* current DAPM context
*/
list_for_each_entry(w, &dapm->card->widgets, list) {
if (!wsink && !(strcmp(w->name, sink))) {
wtsink = w;
if (w->dapm == dapm)
wsink = w;
continue;
}
if (!wsource && !(strcmp(w->name, source))) {
wtsource = w;
if (w->dapm == dapm)
wsource = w;
}
}
/* use widget from another DAPM context if not found from this */
if (!wsink)
wsink = wtsink;
if (!wsource)
wsource = wtsource;
if (wsource == NULL) {
dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
route->source);
return -ENODEV;
}
if (wsink == NULL) {
dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
route->sink);
return -ENODEV;
}
path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
if (!path) if (!path)
...@@ -2247,8 +2352,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, ...@@ -2247,8 +2352,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
path->source = wsource; path->source = wsource;
path->sink = wsink; path->sink = wsink;
path->connected = route->connected; path->connected = connected;
INIT_LIST_HEAD(&path->list); INIT_LIST_HEAD(&path->list);
INIT_LIST_HEAD(&path->list_kcontrol);
INIT_LIST_HEAD(&path->list_source); INIT_LIST_HEAD(&path->list_source);
INIT_LIST_HEAD(&path->list_sink); INIT_LIST_HEAD(&path->list_sink);
...@@ -2268,6 +2374,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, ...@@ -2268,6 +2374,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
wsource->ext = 1; wsource->ext = 1;
} }
dapm_mark_dirty(wsource, "Route added");
dapm_mark_dirty(wsink, "Route added");
/* connect static paths */ /* connect static paths */
if (control == NULL) { if (control == NULL) {
list_add(&path->list, &dapm->card->paths); list_add(&path->list, &dapm->card->paths);
...@@ -2298,6 +2407,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, ...@@ -2298,6 +2407,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
case snd_soc_dapm_dai_in: case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out: case snd_soc_dapm_dai_out:
case snd_soc_dapm_dai_link: case snd_soc_dapm_dai_link:
case snd_soc_dapm_kcontrol:
list_add(&path->list, &dapm->card->paths); list_add(&path->list, &dapm->card->paths);
list_add(&path->list_sink, &wsink->sources); list_add(&path->list_sink, &wsink->sources);
list_add(&path->list_source, &wsource->sinks); list_add(&path->list_source, &wsource->sinks);
...@@ -2329,15 +2439,78 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, ...@@ -2329,15 +2439,78 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
return 0; return 0;
} }
dapm_mark_dirty(wsource, "Route added");
dapm_mark_dirty(wsink, "Route added");
return 0; return 0;
err:
kfree(path);
return ret;
}
static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route)
{
struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
const char *sink;
const char *source;
char prefixed_sink[80];
char prefixed_source[80];
int ret;
if (dapm->codec && dapm->codec->name_prefix) {
snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
dapm->codec->name_prefix, route->sink);
sink = prefixed_sink;
snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
dapm->codec->name_prefix, route->source);
source = prefixed_source;
} else {
sink = route->sink;
source = route->source;
}
/*
* find src and dest widgets over all widgets but favor a widget from
* current DAPM context
*/
list_for_each_entry(w, &dapm->card->widgets, list) {
if (!wsink && !(strcmp(w->name, sink))) {
wtsink = w;
if (w->dapm == dapm)
wsink = w;
continue;
}
if (!wsource && !(strcmp(w->name, source))) {
wtsource = w;
if (w->dapm == dapm)
wsource = w;
}
}
/* use widget from another DAPM context if not found from this */
if (!wsink)
wsink = wtsink;
if (!wsource)
wsource = wtsource;
if (wsource == NULL) {
dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
route->source);
return -ENODEV;
}
if (wsink == NULL) {
dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
route->sink);
return -ENODEV;
}
ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
route->connected);
if (ret)
goto err;
return 0;
err: err:
dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n", dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
source, control, sink); source, route->control, sink);
kfree(path);
return ret; return ret;
} }
...@@ -2541,12 +2714,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); ...@@ -2541,12 +2714,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
*/ */
int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
{ {
struct snd_soc_card *card = dapm->card;
struct snd_soc_dapm_widget *w; struct snd_soc_dapm_widget *w;
unsigned int val; unsigned int val;
mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
list_for_each_entry(w, &dapm->card->widgets, list) list_for_each_entry(w, &card->widgets, list)
{ {
if (w->new) if (w->new)
continue; continue;
...@@ -2556,7 +2730,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) ...@@ -2556,7 +2730,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
sizeof(struct snd_kcontrol *), sizeof(struct snd_kcontrol *),
GFP_KERNEL); GFP_KERNEL);
if (!w->kcontrols) { if (!w->kcontrols) {
mutex_unlock(&dapm->card->dapm_mutex); mutex_unlock(&card->dapm_mutex);
return -ENOMEM; return -ENOMEM;
} }
} }
...@@ -2582,12 +2756,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) ...@@ -2582,12 +2756,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
/* Read the initial power state from the device */ /* Read the initial power state from the device */
if (w->reg >= 0) { if (w->reg >= 0) {
val = soc_widget_read(w, w->reg); val = soc_widget_read(w, w->reg) >> w->shift;
val &= 1 << w->shift; val &= w->mask;
if (w->invert) if (val == w->on_val)
val = !val;
if (val)
w->power = 1; w->power = 1;
} }
...@@ -2597,8 +2768,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) ...@@ -2597,8 +2768,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
dapm_debugfs_add_widget(w); dapm_debugfs_add_widget(w);
} }
dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP); dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
mutex_unlock(&dapm->card->dapm_mutex); mutex_unlock(&card->dapm_mutex);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
...@@ -2615,8 +2786,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); ...@@ -2615,8 +2786,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0]; struct snd_soc_card *card = codec->card;
struct soc_mixer_control *mc = struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg; unsigned int reg = mc->reg;
...@@ -2624,17 +2795,24 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, ...@@ -2624,17 +2795,24 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
int max = mc->max; int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1; unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert; unsigned int invert = mc->invert;
unsigned int val;
if (snd_soc_volsw_is_stereo(mc)) if (snd_soc_volsw_is_stereo(mc))
dev_warn(widget->dapm->dev, dev_warn(codec->dapm.dev,
"ASoC: Control '%s' is stereo, which is not supported\n", "ASoC: Control '%s' is stereo, which is not supported\n",
kcontrol->id.name); kcontrol->id.name);
ucontrol->value.integer.value[0] = mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
(snd_soc_read(widget->codec, reg) >> shift) & mask; if (dapm_kcontrol_is_powered(kcontrol))
val = (snd_soc_read(codec, reg) >> shift) & mask;
else
val = dapm_kcontrol_get_value(kcontrol);
mutex_unlock(&card->dapm_mutex);
if (invert) if (invert)
ucontrol->value.integer.value[0] = ucontrol->value.integer.value[0] = max - val;
max - ucontrol->value.integer.value[0]; else
ucontrol->value.integer.value[0] = val;
return 0; return 0;
} }
...@@ -2652,9 +2830,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); ...@@ -2652,9 +2830,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct snd_soc_card *card = codec->card; struct snd_soc_card *card = codec->card;
struct soc_mixer_control *mc = struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value; (struct soc_mixer_control *)kcontrol->private_value;
...@@ -2666,10 +2842,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, ...@@ -2666,10 +2842,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
unsigned int val; unsigned int val;
int connect, change; int connect, change;
struct snd_soc_dapm_update update; struct snd_soc_dapm_update update;
int wi;
if (snd_soc_volsw_is_stereo(mc)) if (snd_soc_volsw_is_stereo(mc))
dev_warn(widget->dapm->dev, dev_warn(codec->dapm.dev,
"ASoC: Control '%s' is stereo, which is not supported\n", "ASoC: Control '%s' is stereo, which is not supported\n",
kcontrol->id.name); kcontrol->id.name);
...@@ -2678,29 +2853,26 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, ...@@ -2678,29 +2853,26 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
if (invert) if (invert)
val = max - val; val = max - val;
mask = mask << shift;
val = val << shift;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = snd_soc_test_bits(widget->codec, reg, mask, val); dapm_kcontrol_set_value(kcontrol, val);
if (change) {
for (wi = 0; wi < wlist->num_widgets; wi++) {
widget = wlist->widgets[wi];
widget->value = val; mask = mask << shift;
val = val << shift;
update.kcontrol = kcontrol; change = snd_soc_test_bits(codec, reg, mask, val);
update.widget = widget; if (change) {
update.reg = reg; update.kcontrol = kcontrol;
update.mask = mask; update.reg = reg;
update.val = val; update.mask = mask;
widget->dapm->update = &update; update.val = val;
soc_dapm_mixer_update_power(widget, kcontrol, connect); card->update = &update;
widget->dapm->update = NULL; soc_dapm_mixer_update_power(card, kcontrol, connect);
}
card->update = NULL;
} }
mutex_unlock(&card->dapm_mutex); mutex_unlock(&card->dapm_mutex);
...@@ -2720,12 +2892,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); ...@@ -2720,12 +2892,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val; unsigned int val;
val = snd_soc_read(widget->codec, e->reg); val = snd_soc_read(codec, e->reg);
ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
if (e->shift_l != e->shift_r) if (e->shift_l != e->shift_r)
ucontrol->value.enumerated.item[1] = ucontrol->value.enumerated.item[1] =
...@@ -2747,15 +2918,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); ...@@ -2747,15 +2918,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct snd_soc_card *card = codec->card; struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change; unsigned int val, mux, change;
unsigned int mask; unsigned int mask;
struct snd_soc_dapm_update update; struct snd_soc_dapm_update update;
int wi;
if (ucontrol->value.enumerated.item[0] > e->max - 1) if (ucontrol->value.enumerated.item[0] > e->max - 1)
return -EINVAL; return -EINVAL;
...@@ -2771,24 +2939,17 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, ...@@ -2771,24 +2939,17 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val); change = snd_soc_test_bits(codec, e->reg, mask, val);
if (change) { if (change) {
for (wi = 0; wi < wlist->num_widgets; wi++) { update.kcontrol = kcontrol;
widget = wlist->widgets[wi]; update.reg = e->reg;
update.mask = mask;
widget->value = val; update.val = val;
card->update = &update;
update.kcontrol = kcontrol; soc_dapm_mux_update_power(card, kcontrol, mux, e);
update.widget = widget;
update.reg = e->reg;
update.mask = mask;
update.val = val;
widget->dapm->update = &update;
soc_dapm_mux_update_power(widget, kcontrol, mux, e); card->update = NULL;
widget->dapm->update = NULL;
}
} }
mutex_unlock(&card->dapm_mutex); mutex_unlock(&card->dapm_mutex);
...@@ -2806,11 +2967,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); ...@@ -2806,11 +2967,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
ucontrol->value.enumerated.item[0] = widget->value;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
...@@ -2825,30 +2982,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); ...@@ -2825,30 +2982,22 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct snd_soc_card *card = codec->card; struct snd_soc_card *card = codec->card;
unsigned int value;
struct soc_enum *e = struct soc_enum *e =
(struct soc_enum *)kcontrol->private_value; (struct soc_enum *)kcontrol->private_value;
int change; int change;
int wi;
if (ucontrol->value.enumerated.item[0] >= e->max) if (ucontrol->value.enumerated.item[0] >= e->max)
return -EINVAL; return -EINVAL;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = widget->value != ucontrol->value.enumerated.item[0]; value = ucontrol->value.enumerated.item[0];
if (change) { change = dapm_kcontrol_set_value(kcontrol, value);
for (wi = 0; wi < wlist->num_widgets; wi++) { if (change)
widget = wlist->widgets[wi]; soc_dapm_mux_update_power(card, kcontrol, value, e);
widget->value = ucontrol->value.enumerated.item[0];
soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
}
}
mutex_unlock(&card->dapm_mutex); mutex_unlock(&card->dapm_mutex);
return change; return change;
...@@ -2871,12 +3020,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); ...@@ -2871,12 +3020,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int reg_val, val, mux; unsigned int reg_val, val, mux;
reg_val = snd_soc_read(widget->codec, e->reg); reg_val = snd_soc_read(codec, e->reg);
val = (reg_val >> e->shift_l) & e->mask; val = (reg_val >> e->shift_l) & e->mask;
for (mux = 0; mux < e->max; mux++) { for (mux = 0; mux < e->max; mux++) {
if (val == e->values[mux]) if (val == e->values[mux])
...@@ -2912,15 +3060,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); ...@@ -2912,15 +3060,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
struct snd_soc_card *card = codec->card; struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change; unsigned int val, mux, change;
unsigned int mask; unsigned int mask;
struct snd_soc_dapm_update update; struct snd_soc_dapm_update update;
int wi;
if (ucontrol->value.enumerated.item[0] > e->max - 1) if (ucontrol->value.enumerated.item[0] > e->max - 1)
return -EINVAL; return -EINVAL;
...@@ -2936,24 +3081,17 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, ...@@ -2936,24 +3081,17 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val); change = snd_soc_test_bits(codec, e->reg, mask, val);
if (change) { if (change) {
for (wi = 0; wi < wlist->num_widgets; wi++) { update.kcontrol = kcontrol;
widget = wlist->widgets[wi]; update.reg = e->reg;
update.mask = mask;
widget->value = val; update.val = val;
card->update = &update;
update.kcontrol = kcontrol; soc_dapm_mux_update_power(card, kcontrol, mux, e);
update.widget = widget;
update.reg = e->reg;
update.mask = mask;
update.val = val;
widget->dapm->update = &update;
soc_dapm_mux_update_power(widget, kcontrol, mux, e); card->update = NULL;
widget->dapm->update = NULL;
}
} }
mutex_unlock(&card->dapm_mutex); mutex_unlock(&card->dapm_mutex);
...@@ -3050,7 +3188,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, ...@@ -3050,7 +3188,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
return NULL; return NULL;
} }
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) { if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, true); ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0) if (ret != 0)
dev_warn(w->dapm->dev, dev_warn(w->dapm->dev,
...@@ -3097,16 +3235,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, ...@@ -3097,16 +3235,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
case snd_soc_dapm_value_mux: case snd_soc_dapm_value_mux:
w->power_check = dapm_generic_check_power; w->power_check = dapm_generic_check_power;
break; break;
case snd_soc_dapm_adc:
case snd_soc_dapm_aif_out:
case snd_soc_dapm_dai_out: case snd_soc_dapm_dai_out:
w->power_check = dapm_adc_check_power; w->power_check = dapm_adc_check_power;
break; break;
case snd_soc_dapm_dac:
case snd_soc_dapm_aif_in:
case snd_soc_dapm_dai_in: case snd_soc_dapm_dai_in:
w->power_check = dapm_dac_check_power; w->power_check = dapm_dac_check_power;
break; break;
case snd_soc_dapm_adc:
case snd_soc_dapm_aif_out:
case snd_soc_dapm_dac:
case snd_soc_dapm_aif_in:
case snd_soc_dapm_pga: case snd_soc_dapm_pga:
case snd_soc_dapm_out_drv: case snd_soc_dapm_out_drv:
case snd_soc_dapm_input: case snd_soc_dapm_input:
...@@ -3122,6 +3260,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, ...@@ -3122,6 +3260,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
case snd_soc_dapm_supply: case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply: case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply: case snd_soc_dapm_clock_supply:
case snd_soc_dapm_kcontrol:
w->power_check = dapm_supply_check_power; w->power_check = dapm_supply_check_power;
break; break;
default: default:
...@@ -3386,9 +3525,6 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) ...@@ -3386,9 +3525,6 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
{ {
struct snd_soc_dapm_widget *dai_w, *w; struct snd_soc_dapm_widget *dai_w, *w;
struct snd_soc_dai *dai; struct snd_soc_dai *dai;
struct snd_soc_dapm_route r;
memset(&r, 0, sizeof(r));
/* For each DAI widget... */ /* For each DAI widget... */
list_for_each_entry(dai_w, &card->widgets, list) { list_for_each_entry(dai_w, &card->widgets, list) {
...@@ -3415,29 +3551,27 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) ...@@ -3415,29 +3551,27 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
break; break;
} }
if (!w->sname) if (!w->sname || !strstr(w->sname, dai_w->name))
continue; continue;
if (dai->driver->playback.stream_name && if (dai->driver->playback.stream_name &&
strstr(w->sname, strstr(w->sname,
dai->driver->playback.stream_name)) { dai->driver->playback.stream_name)) {
r.source = dai->playback_widget->name;
r.sink = w->name;
dev_dbg(dai->dev, "%s -> %s\n", dev_dbg(dai->dev, "%s -> %s\n",
r.source, r.sink); dai->playback_widget->name, w->name);
snd_soc_dapm_add_route(w->dapm, &r); snd_soc_dapm_add_path(w->dapm,
dai->playback_widget, w, NULL, NULL);
} }
if (dai->driver->capture.stream_name && if (dai->driver->capture.stream_name &&
strstr(w->sname, strstr(w->sname,
dai->driver->capture.stream_name)) { dai->driver->capture.stream_name)) {
r.source = w->name;
r.sink = dai->capture_widget->name;
dev_dbg(dai->dev, "%s -> %s\n", dev_dbg(dai->dev, "%s -> %s\n",
r.source, r.sink); w->name, dai->capture_widget->name);
snd_soc_dapm_add_route(w->dapm, &r); snd_soc_dapm_add_path(w->dapm, w,
dai->capture_widget, NULL, NULL);
} }
} }
} }
...@@ -3499,7 +3633,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, ...@@ -3499,7 +3633,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
} }
} }
dapm_power_widgets(&rtd->card->dapm, event); dapm_power_widgets(rtd->card, event);
} }
/** /**
...@@ -3768,7 +3902,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) ...@@ -3768,7 +3902,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
if (dapm->bias_level == SND_SOC_BIAS_ON) if (dapm->bias_level == SND_SOC_BIAS_ON)
snd_soc_dapm_set_bias_level(dapm, snd_soc_dapm_set_bias_level(dapm,
SND_SOC_BIAS_PREPARE); SND_SOC_BIAS_PREPARE);
dapm_seq_run(dapm, &down_list, 0, false); dapm_seq_run(card, &down_list, 0, false);
if (dapm->bias_level == SND_SOC_BIAS_PREPARE) if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
snd_soc_dapm_set_bias_level(dapm, snd_soc_dapm_set_bias_level(dapm,
SND_SOC_BIAS_STANDBY); SND_SOC_BIAS_STANDBY);
......
...@@ -1833,18 +1833,10 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) ...@@ -1833,18 +1833,10 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
/* Called by DAPM mixer/mux changes to update audio routing between PCMs and /* Called by DAPM mixer/mux changes to update audio routing between PCMs and
* any DAI links. * any DAI links.
*/ */
int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget) int soc_dpcm_runtime_update(struct snd_soc_card *card)
{ {
struct snd_soc_card *card;
int i, old, new, paths; int i, old, new, paths;
if (widget->codec)
card = widget->codec->card;
else if (widget->platform)
card = widget->platform->card;
else
return -EINVAL;
mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
for (i = 0; i < card->num_rtd; i++) { for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dapm_widget_list *list; struct snd_soc_dapm_widget_list *list;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册