aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@linaro.org>2013-11-08 05:43:40 -0500
committerMark Brown <broonie@linaro.org>2013-11-08 05:43:40 -0500
commit88cb5111e8d658abde760605e63db4ecd4f67d82 (patch)
tree4b3b3815e95d4adeacf7d4107bcb665cb4dd6d33
parent86408059df526ea098ac44bbc8a5b0f70a3d53a5 (diff)
parent052901f42f360062f36cc5c0aa6e5ae372fe0895 (diff)
Merge remote-tracking branch 'asoc/topic/twl4030' into asoc-next
-rw-r--r--include/sound/soc-dapm.h4
-rw-r--r--include/sound/soc.h3
-rw-r--r--sound/soc/codecs/twl4030.c80
-rw-r--r--sound/soc/soc-dapm.c46
4 files changed, 70 insertions, 63 deletions
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 27a72d5d4b00..2037c45adfe6 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -286,6 +286,8 @@ struct device;
286 .info = snd_soc_info_volsw, \ 286 .info = snd_soc_info_volsw, \
287 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ 287 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
288 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) } 288 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
289#define SOC_DAPM_SINGLE_VIRT(xname, max) \
290 SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0)
289#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \ 291#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
290{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 292{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
291 .info = snd_soc_info_volsw, \ 293 .info = snd_soc_info_volsw, \
@@ -300,6 +302,8 @@ struct device;
300 .tlv.p = (tlv_array), \ 302 .tlv.p = (tlv_array), \
301 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \ 303 .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
302 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } 304 .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
305#define SOC_DAPM_SINGLE_TLV_VIRT(xname, max, tlv_array) \
306 SOC_DAPM_SINGLE(xname, SND_SOC_NOPM, 0, max, 0, tlv_array)
303#define SOC_DAPM_ENUM(xname, xenum) \ 307#define SOC_DAPM_ENUM(xname, xenum) \
304{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 308{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
305 .info = snd_soc_info_enum_double, \ 309 .info = snd_soc_info_enum_double, \
diff --git a/include/sound/soc.h b/include/sound/soc.h
index fbea72f9cc66..1f741cb24f33 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1051,7 +1051,8 @@ struct snd_soc_pcm_runtime {
1051/* mixer control */ 1051/* mixer control */
1052struct soc_mixer_control { 1052struct soc_mixer_control {
1053 int min, max, platform_max; 1053 int min, max, platform_max;
1054 unsigned int reg, rreg, shift, rshift; 1054 int reg, rreg;
1055 unsigned int shift, rshift;
1055 unsigned int invert:1; 1056 unsigned int invert:1;
1056 unsigned int autodisable:1; 1057 unsigned int autodisable:1;
1057}; 1058};
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 1e3884d6b3fb..dfc51bb425da 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -46,13 +46,7 @@
46/* TWL4030 PMBR1 Register GPIO6 mux bits */ 46/* TWL4030 PMBR1 Register GPIO6 mux bits */
47#define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2) 47#define TWL4030_GPIO6_PWM0_MUTE(value) ((value & 0x03) << 2)
48 48
49/* Shadow register used by the audio driver */ 49#define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1)
50#define TWL4030_REG_SW_SHADOW 0x4A
51#define TWL4030_CACHEREGNUM (TWL4030_REG_SW_SHADOW + 1)
52
53/* TWL4030_REG_SW_SHADOW (0x4A) Fields */
54#define TWL4030_HFL_EN 0x01
55#define TWL4030_HFR_EN 0x02
56 50
57/* 51/*
58 * twl4030 register cache & default register settings 52 * twl4030 register cache & default register settings
@@ -132,7 +126,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
132 0x00, /* REG_VIBRA_PWM_SET (0x47) */ 126 0x00, /* REG_VIBRA_PWM_SET (0x47) */
133 0x00, /* REG_ANAMIC_GAIN (0x48) */ 127 0x00, /* REG_ANAMIC_GAIN (0x48) */
134 0x00, /* REG_MISC_SET_2 (0x49) */ 128 0x00, /* REG_MISC_SET_2 (0x49) */
135 0x00, /* REG_SW_SHADOW (0x4A) - Shadow, non HW register */
136}; 129};
137 130
138/* codec private data */ 131/* codec private data */
@@ -198,42 +191,41 @@ static int twl4030_write(struct snd_soc_codec *codec,
198 int write_to_reg = 0; 191 int write_to_reg = 0;
199 192
200 twl4030_write_reg_cache(codec, reg, value); 193 twl4030_write_reg_cache(codec, reg, value);
201 if (likely(reg < TWL4030_REG_SW_SHADOW)) { 194 /* Decide if the given register can be written */
202 /* Decide if the given register can be written */ 195 switch (reg) {
203 switch (reg) { 196 case TWL4030_REG_EAR_CTL:
204 case TWL4030_REG_EAR_CTL: 197 if (twl4030->earpiece_enabled)
205 if (twl4030->earpiece_enabled)
206 write_to_reg = 1;
207 break;
208 case TWL4030_REG_PREDL_CTL:
209 if (twl4030->predrivel_enabled)
210 write_to_reg = 1;
211 break;
212 case TWL4030_REG_PREDR_CTL:
213 if (twl4030->predriver_enabled)
214 write_to_reg = 1;
215 break;
216 case TWL4030_REG_PRECKL_CTL:
217 if (twl4030->carkitl_enabled)
218 write_to_reg = 1;
219 break;
220 case TWL4030_REG_PRECKR_CTL:
221 if (twl4030->carkitr_enabled)
222 write_to_reg = 1;
223 break;
224 case TWL4030_REG_HS_GAIN_SET:
225 if (twl4030->hsl_enabled || twl4030->hsr_enabled)
226 write_to_reg = 1;
227 break;
228 default:
229 /* All other register can be written */
230 write_to_reg = 1; 198 write_to_reg = 1;
231 break; 199 break;
232 } 200 case TWL4030_REG_PREDL_CTL:
233 if (write_to_reg) 201 if (twl4030->predrivel_enabled)
234 return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, 202 write_to_reg = 1;
235 value, reg); 203 break;
204 case TWL4030_REG_PREDR_CTL:
205 if (twl4030->predriver_enabled)
206 write_to_reg = 1;
207 break;
208 case TWL4030_REG_PRECKL_CTL:
209 if (twl4030->carkitl_enabled)
210 write_to_reg = 1;
211 break;
212 case TWL4030_REG_PRECKR_CTL:
213 if (twl4030->carkitr_enabled)
214 write_to_reg = 1;
215 break;
216 case TWL4030_REG_HS_GAIN_SET:
217 if (twl4030->hsl_enabled || twl4030->hsr_enabled)
218 write_to_reg = 1;
219 break;
220 default:
221 /* All other register can be written */
222 write_to_reg = 1;
223 break;
236 } 224 }
225 if (write_to_reg)
226 return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
227 value, reg);
228
237 return 0; 229 return 0;
238} 230}
239 231
@@ -532,7 +524,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum);
532 524
533/* Handsfree Left virtual mute */ 525/* Handsfree Left virtual mute */
534static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = 526static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control =
535 SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 0, 1, 0); 527 SOC_DAPM_SINGLE_VIRT("Switch", 1);
536 528
537/* Handsfree Right */ 529/* Handsfree Right */
538static const char *twl4030_handsfreer_texts[] = 530static const char *twl4030_handsfreer_texts[] =
@@ -548,7 +540,7 @@ SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum);
548 540
549/* Handsfree Right virtual mute */ 541/* Handsfree Right virtual mute */
550static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = 542static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control =
551 SOC_DAPM_SINGLE("Switch", TWL4030_REG_SW_SHADOW, 1, 1, 0); 543 SOC_DAPM_SINGLE_VIRT("Switch", 1);
552 544
553/* Vibra */ 545/* Vibra */
554/* Vibra audio path selection */ 546/* Vibra audio path selection */
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index b2949aed1ac2..0580d144a8c9 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,
499 int val; 499 int val;
500 struct soc_mixer_control *mc = (struct soc_mixer_control *) 500 struct soc_mixer_control *mc = (struct soc_mixer_control *)
501 w->kcontrol_news[i].private_value; 501 w->kcontrol_news[i].private_value;
502 unsigned int reg = mc->reg; 502 int reg = mc->reg;
503 unsigned int shift = mc->shift; 503 unsigned int shift = mc->shift;
504 int max = mc->max; 504 int max = mc->max;
505 unsigned int mask = (1 << fls(max)) - 1; 505 unsigned int mask = (1 << fls(max)) - 1;
506 unsigned int invert = mc->invert; 506 unsigned int invert = mc->invert;
507 507
508 val = soc_widget_read(w, reg); 508 if (reg != SND_SOC_NOPM) {
509 val = (val >> shift) & mask; 509 val = soc_widget_read(w, reg);
510 if (invert) 510 val = (val >> shift) & mask;
511 val = max - val; 511 if (invert)
512 val = max - val;
513 p->connect = !!val;
514 } else {
515 p->connect = 0;
516 }
512 517
513 p->connect = !!val;
514 } 518 }
515 break; 519 break;
516 case snd_soc_dapm_mux: { 520 case snd_soc_dapm_mux: {
@@ -1840,6 +1844,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event)
1840 */ 1844 */
1841 switch (w->id) { 1845 switch (w->id) {
1842 case snd_soc_dapm_siggen: 1846 case snd_soc_dapm_siggen:
1847 case snd_soc_dapm_vmid:
1843 break; 1848 break;
1844 case snd_soc_dapm_supply: 1849 case snd_soc_dapm_supply:
1845 case snd_soc_dapm_regulator_supply: 1850 case snd_soc_dapm_regulator_supply:
@@ -2791,7 +2796,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2791 struct snd_soc_card *card = codec->card; 2796 struct snd_soc_card *card = codec->card;
2792 struct soc_mixer_control *mc = 2797 struct soc_mixer_control *mc =
2793 (struct soc_mixer_control *)kcontrol->private_value; 2798 (struct soc_mixer_control *)kcontrol->private_value;
2794 unsigned int reg = mc->reg; 2799 int reg = mc->reg;
2795 unsigned int shift = mc->shift; 2800 unsigned int shift = mc->shift;
2796 int max = mc->max; 2801 int max = mc->max;
2797 unsigned int mask = (1 << fls(max)) - 1; 2802 unsigned int mask = (1 << fls(max)) - 1;
@@ -2804,7 +2809,7 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
2804 kcontrol->id.name); 2809 kcontrol->id.name);
2805 2810
2806 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); 2811 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2807 if (dapm_kcontrol_is_powered(kcontrol)) 2812 if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM)
2808 val = (snd_soc_read(codec, reg) >> shift) & mask; 2813 val = (snd_soc_read(codec, reg) >> shift) & mask;
2809 else 2814 else
2810 val = dapm_kcontrol_get_value(kcontrol); 2815 val = dapm_kcontrol_get_value(kcontrol);
@@ -2835,7 +2840,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2835 struct snd_soc_card *card = codec->card; 2840 struct snd_soc_card *card = codec->card;
2836 struct soc_mixer_control *mc = 2841 struct soc_mixer_control *mc =
2837 (struct soc_mixer_control *)kcontrol->private_value; 2842 (struct soc_mixer_control *)kcontrol->private_value;
2838 unsigned int reg = mc->reg; 2843 int reg = mc->reg;
2839 unsigned int shift = mc->shift; 2844 unsigned int shift = mc->shift;
2840 int max = mc->max; 2845 int max = mc->max;
2841 unsigned int mask = (1 << fls(max)) - 1; 2846 unsigned int mask = (1 << fls(max)) - 1;
@@ -2857,19 +2862,24 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
2857 2862
2858 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); 2863 mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
2859 2864
2860 dapm_kcontrol_set_value(kcontrol, val); 2865 change = dapm_kcontrol_set_value(kcontrol, val);
2861 2866
2862 mask = mask << shift; 2867 if (reg != SND_SOC_NOPM) {
2863 val = val << shift; 2868 mask = mask << shift;
2869 val = val << shift;
2870
2871 change = snd_soc_test_bits(codec, reg, mask, val);
2872 }
2864 2873
2865 change = snd_soc_test_bits(codec, reg, mask, val);
2866 if (change) { 2874 if (change) {
2867 update.kcontrol = kcontrol; 2875 if (reg != SND_SOC_NOPM) {
2868 update.reg = reg; 2876 update.kcontrol = kcontrol;
2869 update.mask = mask; 2877 update.reg = reg;
2870 update.val = val; 2878 update.mask = mask;
2879 update.val = val;
2871 2880
2872 card->update = &update; 2881 card->update = &update;
2882 }
2873 2883
2874 soc_dapm_mixer_update_power(card, kcontrol, connect); 2884 soc_dapm_mixer_update_power(card, kcontrol, connect);
2875 2885