[alsa-devel] [PATCH 1/3] ASoC: dapm: Add support for virtual mixer controls
This patch adds support for virtual DAPM mixer controls. They are similar to virtual DAPM enums. There is no hardware register backing the control, so changing the control's value wont have any direct effect on the hardware. But it still influences the DAPM graph by causing the path it sits on to be connected or disconnected. This in turn can cause power changes for some of the widgets on the DAPM graph, which will then modify the hardware state.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- include/sound/soc-dapm.h | 4 ++++ include/sound/soc.h | 3 ++- sound/soc/soc-dapm.c | 45 +++++++++++++++++++++++++++------------------ 3 files changed, 33 insertions(+), 19 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 27a72d5..2037c45 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -286,6 +286,8 @@ struct device; .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_VIRT(xname, max) \ + SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0) #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, \ @@ -300,6 +302,8 @@ struct device; .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_SINGLE_TLV_VIRT(xname, max, tlv_array) \ + SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array) #define SOC_DAPM_ENUM(xname, xenum) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_double, \ diff --git a/include/sound/soc.h b/include/sound/soc.h index 6dd329a..af1678c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1049,7 +1049,8 @@ struct snd_soc_pcm_runtime { /* mixer control */ struct soc_mixer_control { int min, max, platform_max; - unsigned int reg, rreg, shift, rshift; + int reg, rreg; + unsigned int shift, rshift; unsigned int invert:1; unsigned int autodisable:1; }; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c17c14c..25b9554 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -499,18 +499,22 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, int val; struct soc_mixer_control *mc = (struct soc_mixer_control *) w->kcontrol_news[i].private_value; - unsigned int reg = mc->reg; + int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert;
- val = soc_widget_read(w, reg); - val = (val >> shift) & mask; - if (invert) - val = max - val; + if (reg != SND_SOC_NOPM) { + val = soc_widget_read(w, reg); + val = (val >> shift) & mask; + if (invert) + val = max - val; + p->connect = !!val; + } else { + p->connect = 0; + }
- p->connect = !!val; } break; case snd_soc_dapm_mux: { @@ -2791,7 +2795,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = codec->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; + int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; @@ -2804,7 +2808,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, kcontrol->id.name);
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - if (dapm_kcontrol_is_powered(kcontrol)) + if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) val = (snd_soc_read(codec, reg) >> shift) & mask; else val = dapm_kcontrol_get_value(kcontrol); @@ -2835,7 +2839,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = codec->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; + int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; @@ -2857,19 +2861,24 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- dapm_kcontrol_set_value(kcontrol, val); + change = dapm_kcontrol_set_value(kcontrol, val);
- mask = mask << shift; - val = val << shift; + if (reg != SND_SOC_NOPM) { + mask = mask << shift; + val = val << shift; + + change = snd_soc_test_bits(codec, reg, mask, val); + }
- change = snd_soc_test_bits(codec, reg, mask, val); if (change) { - update.kcontrol = kcontrol; - update.reg = reg; - update.mask = mask; - update.val = val; + if (reg != SND_SOC_NOPM) { + update.kcontrol = kcontrol; + update.reg = reg; + update.mask = mask; + update.val = val;
- card->update = &update; + card->update = &update; + }
soc_dapm_mixer_update_power(card, kcontrol, connect);
By using the new virtual DAPM mixer controls it is possible to remove the twl4030 specific implementation of virtual controls.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/codecs/twl4030.c | 80 +++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 44 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1e3884d..dfc51bb 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -46,13 +46,7 @@ /* TWL4030 PMBR1 Register GPIO6 mux bits */ #define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2)
-/* Shadow register used by the audio driver */ -#define TWL4030_REG_SW_SHADOW 0x4A -#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1) - -/* TWL4030_REG_SW_SHADOW (0x4A) Fields */ -#define TWL4030_HFL_EN 0x01 -#define TWL4030_HFR_EN 0x02 +#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1)
/* * twl4030 register cache & default register settings @@ -132,7 +126,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_VIBRA_PWM_SET (0x47) */ 0x00, /* REG_ANAMIC_GAIN (0x48) */ 0x00, /* REG_MISC_SET_2 (0x49) */ - 0x00, /* REG_SW_SHADOW (0x4A) - Shadow, non HW register */ };
/* codec private data */ @@ -198,42 +191,41 @@ static int twl4030_write(struct snd_soc_codec *codec, int write_to_reg = 0;
twl4030_write_reg_cache(codec, reg, value); - if (likely(reg < TWL4030_REG_SW_SHADOW)) { - /* Decide if the given register can be written */ - switch (reg) { - case TWL4030_REG_EAR_CTL: - if (twl4030->earpiece_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_PREDL_CTL: - if (twl4030->predrivel_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_PREDR_CTL: - if (twl4030->predriver_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_PRECKL_CTL: - if (twl4030->carkitl_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_PRECKR_CTL: - if (twl4030->carkitr_enabled) - write_to_reg = 1; - break; - case TWL4030_REG_HS_GAIN_SET: - if (twl4030->hsl_enabled || twl4030->hsr_enabled) - write_to_reg = 1; - break; - default: - /* All other register can be written */ + /* Decide if the given register can be written */ + switch (reg) { + case TWL4030_REG_EAR_CTL: + if (twl4030->earpiece_enabled) write_to_reg = 1; - break; - } - if (write_to_reg) - return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - value, reg); + break; + case TWL4030_REG_PREDL_CTL: + if (twl4030->predrivel_enabled) + write_to_reg = 1; + break; + case TWL4030_REG_PREDR_CTL: + if (twl4030->predriver_enabled) + write_to_reg = 1; + break; + case TWL4030_REG_PRECKL_CTL: + if (twl4030->carkitl_enabled) + write_to_reg = 1; + break; + case TWL4030_REG_PRECKR_CTL: + if (twl4030->carkitr_enabled) + write_to_reg = 1; + break; + case TWL4030_REG_HS_GAIN_SET: + if (twl4030->hsl_enabled || twl4030->hsr_enabled) + write_to_reg = 1; + break; + default: + /* All other register can be written */ + write_to_reg = 1; + break; } + if (write_to_reg) + return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, + value, reg); + return 0; }
@@ -532,7 +524,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
/* Handsfree Left virtual mute */ static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = - SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0); + SOC_DAPM_SINGLE_VIRT("Switch", 1);
/* Handsfree Right */ static const char *twl4030_handsfreer_texts[] = @@ -548,7 +540,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
/* Handsfree Right virtual mute */ static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = - SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0); + SOC_DAPM_SINGLE_VIRT("Switch", 1);
/* Vibra */ /* Vibra audio path selection */
On 10/06/2013 02:43 PM, Lars-Peter Clausen wrote:
By using the new virtual DAPM mixer controls it is possible to remove the twl4030 specific implementation of virtual controls.
Acked-by: Peter Ujfalusi peter.ujflausi@ti.com
Signed-off-by: Lars-Peter Clausen lars@metafoo.de
sound/soc/codecs/twl4030.c | 80 +++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 44 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1e3884d..dfc51bb 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -46,13 +46,7 @@ /* TWL4030 PMBR1 Register GPIO6 mux bits */ #define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2)
-/* Shadow register used by the audio driver */ -#define TWL4030_REG_SW_SHADOW 0x4A -#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
-/* TWL4030_REG_SW_SHADOW (0x4A) Fields */ -#define TWL4030_HFL_EN 0x01 -#define TWL4030_HFR_EN 0x02 +#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1)
/*
- twl4030 register cache & default register settings
@@ -132,7 +126,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_VIBRA_PWM_SET (0x47) */ 0x00, /* REG_ANAMIC_GAIN (0x48) */ 0x00, /* REG_MISC_SET_2 (0x49) */
- 0x00, /* REG_SW_SHADOW (0x4A) - Shadow, non HW register */
};
/* codec private data */ @@ -198,42 +191,41 @@ static int twl4030_write(struct snd_soc_codec *codec, int write_to_reg = 0;
twl4030_write_reg_cache(codec, reg, value);
- if (likely(reg < TWL4030_REG_SW_SHADOW)) {
/* Decide if the given register can be written */
switch (reg) {
case TWL4030_REG_EAR_CTL:
if (twl4030->earpiece_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_PREDL_CTL:
if (twl4030->predrivel_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_PREDR_CTL:
if (twl4030->predriver_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_PRECKL_CTL:
if (twl4030->carkitl_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_PRECKR_CTL:
if (twl4030->carkitr_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_HS_GAIN_SET:
if (twl4030->hsl_enabled || twl4030->hsr_enabled)
write_to_reg = 1;
break;
default:
/* All other register can be written */
- /* Decide if the given register can be written */
- switch (reg) {
- case TWL4030_REG_EAR_CTL:
if (twl4030->earpiece_enabled) write_to_reg = 1;
break;
}
if (write_to_reg)
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
value, reg);
break;
- case TWL4030_REG_PREDL_CTL:
if (twl4030->predrivel_enabled)
write_to_reg = 1;
break;
- case TWL4030_REG_PREDR_CTL:
if (twl4030->predriver_enabled)
write_to_reg = 1;
break;
- case TWL4030_REG_PRECKL_CTL:
if (twl4030->carkitl_enabled)
write_to_reg = 1;
break;
- case TWL4030_REG_PRECKR_CTL:
if (twl4030->carkitr_enabled)
write_to_reg = 1;
break;
- case TWL4030_REG_HS_GAIN_SET:
if (twl4030->hsl_enabled || twl4030->hsr_enabled)
write_to_reg = 1;
break;
- default:
/* All other register can be written */
write_to_reg = 1;
}break;
- if (write_to_reg)
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
value, reg);
- return 0;
}
@@ -532,7 +524,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
/* Handsfree Left virtual mute */ static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
- SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0);
- SOC_DAPM_SINGLE_VIRT("Switch", 1);
/* Handsfree Right */ static const char *twl4030_handsfreer_texts[] = @@ -548,7 +540,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
/* Handsfree Right virtual mute */ static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
- SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0);
- SOC_DAPM_SINGLE_VIRT("Switch", 1);
/* Vibra */ /* Vibra audio path selection */
On 10/07/2013 12:07 PM, Peter Ujfalusi wrote:
On 10/06/2013 02:43 PM, Lars-Peter Clausen wrote:
By using the new virtual DAPM mixer controls it is possible to remove the twl4030 specific implementation of virtual controls.
Acked-by: Peter Ujfalusi peter.ujflausi@ti.com
Argh, typo in my e-mail address:
Acked-by: Peter Ujfalusi peter.ujfalusi@ti.com
Signed-off-by: Lars-Peter Clausen lars@metafoo.de
sound/soc/codecs/twl4030.c | 80 +++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 44 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 1e3884d..dfc51bb 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -46,13 +46,7 @@ /* TWL4030 PMBR1 Register GPIO6 mux bits */ #define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2)
-/* Shadow register used by the audio driver */ -#define TWL4030_REG_SW_SHADOW 0x4A -#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
-/* TWL4030_REG_SW_SHADOW (0x4A) Fields */ -#define TWL4030_HFL_EN 0x01 -#define TWL4030_HFR_EN 0x02 +#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1)
/*
- twl4030 register cache & default register settings
@@ -132,7 +126,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { 0x00, /* REG_VIBRA_PWM_SET (0x47) */ 0x00, /* REG_ANAMIC_GAIN (0x48) */ 0x00, /* REG_MISC_SET_2 (0x49) */
- 0x00, /* REG_SW_SHADOW (0x4A) - Shadow, non HW register */
};
/* codec private data */ @@ -198,42 +191,41 @@ static int twl4030_write(struct snd_soc_codec *codec, int write_to_reg = 0;
twl4030_write_reg_cache(codec, reg, value);
- if (likely(reg < TWL4030_REG_SW_SHADOW)) {
/* Decide if the given register can be written */
switch (reg) {
case TWL4030_REG_EAR_CTL:
if (twl4030->earpiece_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_PREDL_CTL:
if (twl4030->predrivel_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_PREDR_CTL:
if (twl4030->predriver_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_PRECKL_CTL:
if (twl4030->carkitl_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_PRECKR_CTL:
if (twl4030->carkitr_enabled)
write_to_reg = 1;
break;
case TWL4030_REG_HS_GAIN_SET:
if (twl4030->hsl_enabled || twl4030->hsr_enabled)
write_to_reg = 1;
break;
default:
/* All other register can be written */
- /* Decide if the given register can be written */
- switch (reg) {
- case TWL4030_REG_EAR_CTL:
if (twl4030->earpiece_enabled) write_to_reg = 1;
break;
}
if (write_to_reg)
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
value, reg);
break;
- case TWL4030_REG_PREDL_CTL:
if (twl4030->predrivel_enabled)
write_to_reg = 1;
break;
- case TWL4030_REG_PREDR_CTL:
if (twl4030->predriver_enabled)
write_to_reg = 1;
break;
- case TWL4030_REG_PRECKL_CTL:
if (twl4030->carkitl_enabled)
write_to_reg = 1;
break;
- case TWL4030_REG_PRECKR_CTL:
if (twl4030->carkitr_enabled)
write_to_reg = 1;
break;
- case TWL4030_REG_HS_GAIN_SET:
if (twl4030->hsl_enabled || twl4030->hsr_enabled)
write_to_reg = 1;
break;
- default:
/* All other register can be written */
write_to_reg = 1;
}break;
- if (write_to_reg)
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
value, reg);
- return 0;
}
@@ -532,7 +524,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
/* Handsfree Left virtual mute */ static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
- SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0);
- SOC_DAPM_SINGLE_VIRT("Switch", 1);
/* Handsfree Right */ static const char *twl4030_handsfreer_texts[] = @@ -548,7 +540,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
/* Handsfree Right virtual mute */ static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
- SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0);
- SOC_DAPM_SINGLE_VIRT("Switch", 1);
/* Vibra */ /* Vibra audio path selection */
On Sun, Oct 06, 2013 at 01:43:50PM +0200, Lars-Peter Clausen wrote:
By using the new virtual DAPM mixer controls it is possible to remove the twl4030 specific implementation of virtual controls.
Applied, thanks.
By using the new virtual DAPM mixer controls it is possible to remove the twl6040 specific implementation of virtual controls.
Signed-off-by: Lars-Peter Clausen lars@metafoo.de --- sound/soc/codecs/twl6040.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-)
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 35059a2..f2f4bcb 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -54,12 +54,7 @@ enum twl6040_dai_id { #define TWL6040_OUTHF_0dB 0x03 #define TWL6040_OUTHF_M52dB 0x1D
-/* Shadow register used by the driver */ -#define TWL6040_REG_SW_SHADOW 0x2F -#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1) - -/* TWL6040_REG_SW_SHADOW (0x2F) fields */ -#define TWL6040_EAR_PATH_ENABLE 0x01 +#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
struct twl6040_jack_data { struct snd_soc_jack *jack; @@ -135,8 +130,6 @@ static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = { 0x00, /* REG_HFOTRIM 0x2C */ 0x09, /* REG_ACCCTL 0x2D */ 0x00, /* REG_STATUS 0x2E (ro) */ - - 0x00, /* REG_SW_SHADOW 0x2F - Shadow, non HW register */ };
/* List of registers to be restored after power up */ @@ -220,12 +213,8 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, if (reg >= TWL6040_CACHEREGNUM) return -EIO;
- if (likely(reg < TWL6040_REG_SW_SHADOW)) { - value = twl6040_reg_read(twl6040, reg); - twl6040_write_reg_cache(codec, reg, value); - } else { - value = twl6040_read_reg_cache(codec, reg); - } + value = twl6040_reg_read(twl6040, reg); + twl6040_write_reg_cache(codec, reg, value);
return value; } @@ -261,8 +250,7 @@ static int twl6040_write(struct snd_soc_codec *codec, return -EIO;
twl6040_write_reg_cache(codec, reg, value); - if (likely(reg < TWL6040_REG_SW_SHADOW) && - twl6040_is_path_unmuted(codec, reg)) + if (twl6040_is_path_unmuted(codec, reg)) return twl6040_reg_write(twl6040, reg, value); else return 0; @@ -555,7 +543,7 @@ static const struct snd_kcontrol_new hfr_mux_controls = SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
static const struct snd_kcontrol_new ep_path_enable_control = - SOC_DAPM_SINGLE("Switch", TWL6040_REG_SW_SHADOW, 0, 1, 0); + SOC_DAPM_SINGLE_VIRT("Switch", 1);
static const struct snd_kcontrol_new auxl_switch_control = SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0);
On 10/06/2013 02:43 PM, Lars-Peter Clausen wrote:
By using the new virtual DAPM mixer controls it is possible to remove the twl6040 specific implementation of virtual controls.
Acked-by: Peter Ujfalusi peter.ujflausi@ti.com
Signed-off-by: Lars-Peter Clausen lars@metafoo.de
sound/soc/codecs/twl6040.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-)
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 35059a2..f2f4bcb 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -54,12 +54,7 @@ enum twl6040_dai_id { #define TWL6040_OUTHF_0dB 0x03 #define TWL6040_OUTHF_M52dB 0x1D
-/* Shadow register used by the driver */ -#define TWL6040_REG_SW_SHADOW 0x2F -#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1)
-/* TWL6040_REG_SW_SHADOW (0x2F) fields */ -#define TWL6040_EAR_PATH_ENABLE 0x01 +#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
struct twl6040_jack_data { struct snd_soc_jack *jack; @@ -135,8 +130,6 @@ static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = { 0x00, /* REG_HFOTRIM 0x2C */ 0x09, /* REG_ACCCTL 0x2D */ 0x00, /* REG_STATUS 0x2E (ro) */
- 0x00, /* REG_SW_SHADOW 0x2F - Shadow, non HW register */
};
/* List of registers to be restored after power up */ @@ -220,12 +213,8 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, if (reg >= TWL6040_CACHEREGNUM) return -EIO;
- if (likely(reg < TWL6040_REG_SW_SHADOW)) {
value = twl6040_reg_read(twl6040, reg);
twl6040_write_reg_cache(codec, reg, value);
- } else {
value = twl6040_read_reg_cache(codec, reg);
- }
value = twl6040_reg_read(twl6040, reg);
twl6040_write_reg_cache(codec, reg, value);
return value;
} @@ -261,8 +250,7 @@ static int twl6040_write(struct snd_soc_codec *codec, return -EIO;
twl6040_write_reg_cache(codec, reg, value);
- if (likely(reg < TWL6040_REG_SW_SHADOW) &&
twl6040_is_path_unmuted(codec, reg))
- if (twl6040_is_path_unmuted(codec, reg)) return twl6040_reg_write(twl6040, reg, value); else return 0;
@@ -555,7 +543,7 @@ static const struct snd_kcontrol_new hfr_mux_controls = SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
static const struct snd_kcontrol_new ep_path_enable_control =
- SOC_DAPM_SINGLE("Switch", TWL6040_REG_SW_SHADOW, 0, 1, 0);
- SOC_DAPM_SINGLE_VIRT("Switch", 1);
static const struct snd_kcontrol_new auxl_switch_control = SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0);
On 10/07/2013 12:07 PM, Peter Ujfalusi wrote:
On 10/06/2013 02:43 PM, Lars-Peter Clausen wrote:
By using the new virtual DAPM mixer controls it is possible to remove the twl6040 specific implementation of virtual controls.
Acked-by: Peter Ujfalusi peter.ujflausi@ti.com
Same typo as with the twl4030 patch: Acked-by: Peter Ujfalusi peter.ujfalusi@ti.com
Signed-off-by: Lars-Peter Clausen lars@metafoo.de
sound/soc/codecs/twl6040.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-)
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 35059a2..f2f4bcb 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -54,12 +54,7 @@ enum twl6040_dai_id { #define TWL6040_OUTHF_0dB 0x03 #define TWL6040_OUTHF_M52dB 0x1D
-/* Shadow register used by the driver */ -#define TWL6040_REG_SW_SHADOW 0x2F -#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1)
-/* TWL6040_REG_SW_SHADOW (0x2F) fields */ -#define TWL6040_EAR_PATH_ENABLE 0x01 +#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
struct twl6040_jack_data { struct snd_soc_jack *jack; @@ -135,8 +130,6 @@ static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = { 0x00, /* REG_HFOTRIM 0x2C */ 0x09, /* REG_ACCCTL 0x2D */ 0x00, /* REG_STATUS 0x2E (ro) */
- 0x00, /* REG_SW_SHADOW 0x2F - Shadow, non HW register */
};
/* List of registers to be restored after power up */ @@ -220,12 +213,8 @@ static int twl6040_read_reg_volatile(struct snd_soc_codec *codec, if (reg >= TWL6040_CACHEREGNUM) return -EIO;
- if (likely(reg < TWL6040_REG_SW_SHADOW)) {
value = twl6040_reg_read(twl6040, reg);
twl6040_write_reg_cache(codec, reg, value);
- } else {
value = twl6040_read_reg_cache(codec, reg);
- }
value = twl6040_reg_read(twl6040, reg);
twl6040_write_reg_cache(codec, reg, value);
return value;
} @@ -261,8 +250,7 @@ static int twl6040_write(struct snd_soc_codec *codec, return -EIO;
twl6040_write_reg_cache(codec, reg, value);
- if (likely(reg < TWL6040_REG_SW_SHADOW) &&
twl6040_is_path_unmuted(codec, reg))
- if (twl6040_is_path_unmuted(codec, reg)) return twl6040_reg_write(twl6040, reg, value); else return 0;
@@ -555,7 +543,7 @@ static const struct snd_kcontrol_new hfr_mux_controls = SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
static const struct snd_kcontrol_new ep_path_enable_control =
- SOC_DAPM_SINGLE("Switch", TWL6040_REG_SW_SHADOW, 0, 1, 0);
- SOC_DAPM_SINGLE_VIRT("Switch", 1);
static const struct snd_kcontrol_new auxl_switch_control = SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 6, 1, 0);
On Sun, Oct 06, 2013 at 01:43:51PM +0200, Lars-Peter Clausen wrote:
By using the new virtual DAPM mixer controls it is possible to remove the twl6040 specific implementation of virtual controls.
Applied, thanks.
On 10/06/2013 02:43 PM, Lars-Peter Clausen wrote:
This patch adds support for virtual DAPM mixer controls. They are similar to virtual DAPM enums. There is no hardware register backing the control, so changing the control's value wont have any direct effect on the hardware. But it still influences the DAPM graph by causing the path it sits on to be connected or disconnected. This in turn can cause power changes for some of the widgets on the DAPM graph, which will then modify the hardware state.
Tested-by: Peter Ujfalusi peter.ujfalusi@ti.com
Signed-off-by: Lars-Peter Clausen lars@metafoo.de
include/sound/soc-dapm.h | 4 ++++ include/sound/soc.h | 3 ++- sound/soc/soc-dapm.c | 45 +++++++++++++++++++++++++++------------------ 3 files changed, 33 insertions(+), 19 deletions(-)
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 27a72d5..2037c45 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -286,6 +286,8 @@ struct device; .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_VIRT(xname, max) \
- SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0)
#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_volsw, \ @@ -300,6 +302,8 @@ struct device; .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_SINGLE_TLV_VIRT(xname, max, tlv_array) \
- SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array)
#define SOC_DAPM_ENUM(xname, xenum) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_double, \ diff --git a/include/sound/soc.h b/include/sound/soc.h index 6dd329a..af1678c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1049,7 +1049,8 @@ struct snd_soc_pcm_runtime { /* mixer control */ struct soc_mixer_control { int min, max, platform_max;
- unsigned int reg, rreg, shift, rshift;
- int reg, rreg;
- unsigned int shift, rshift; unsigned int invert:1; unsigned int autodisable:1;
}; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c17c14c..25b9554 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -499,18 +499,22 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, int val; struct soc_mixer_control *mc = (struct soc_mixer_control *) w->kcontrol_news[i].private_value;
unsigned int reg = mc->reg;
unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert;int reg = mc->reg;
val = soc_widget_read(w, reg);
val = (val >> shift) & mask;
if (invert)
val = max - val;
if (reg != SND_SOC_NOPM) {
val = soc_widget_read(w, reg);
val = (val >> shift) & mask;
if (invert)
val = max - val;
p->connect = !!val;
} else {
p->connect = 0;
}
} break; case snd_soc_dapm_mux: {p->connect = !!val;
@@ -2791,7 +2795,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = codec->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1;
@@ -2804,7 +2808,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, kcontrol->id.name);
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- if (dapm_kcontrol_is_powered(kcontrol))
- if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) val = (snd_soc_read(codec, reg) >> shift) & mask; else val = dapm_kcontrol_get_value(kcontrol);
@@ -2835,7 +2839,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = codec->card; struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; unsigned int mask = (1 << fls(max)) - 1;
@@ -2857,19 +2861,24 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- dapm_kcontrol_set_value(kcontrol, val);
- change = dapm_kcontrol_set_value(kcontrol, val);
- mask = mask << shift;
- val = val << shift;
- if (reg != SND_SOC_NOPM) {
mask = mask << shift;
val = val << shift;
change = snd_soc_test_bits(codec, reg, mask, val);
- }
- change = snd_soc_test_bits(codec, reg, mask, val); if (change) {
update.kcontrol = kcontrol;
update.reg = reg;
update.mask = mask;
update.val = val;
if (reg != SND_SOC_NOPM) {
update.kcontrol = kcontrol;
update.reg = reg;
update.mask = mask;
update.val = val;
card->update = &update;
card->update = &update;
}
soc_dapm_mixer_update_power(card, kcontrol, connect);
On Sun, Oct 06, 2013 at 01:43:49PM +0200, Lars-Peter Clausen wrote:
This patch adds support for virtual DAPM mixer controls. They are similar to virtual DAPM enums. There is no hardware register backing the control, so changing the control's value wont have any direct effect on the hardware. But it still influences the DAPM graph by causing the path it sits on to be connected or disconnected. This in turn can cause power changes for some of the widgets on the DAPM graph, which will then modify the hardware state.
Applied, thanks.
participants (3)
-
Lars-Peter Clausen
-
Mark Brown
-
Peter Ujfalusi