diff options
author | Mark Brown <broonie@linaro.org> | 2013-11-08 05:43:40 -0500 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-11-08 05:43:40 -0500 |
commit | 88cb5111e8d658abde760605e63db4ecd4f67d82 (patch) | |
tree | 4b3b3815e95d4adeacf7d4107bcb665cb4dd6d33 | |
parent | 86408059df526ea098ac44bbc8a5b0f70a3d53a5 (diff) | |
parent | 052901f42f360062f36cc5c0aa6e5ae372fe0895 (diff) |
Merge remote-tracking branch 'asoc/topic/twl4030' into asoc-next
-rw-r--r-- | include/sound/soc-dapm.h | 4 | ||||
-rw-r--r-- | include/sound/soc.h | 3 | ||||
-rw-r--r-- | sound/soc/codecs/twl4030.c | 80 | ||||
-rw-r--r-- | sound/soc/soc-dapm.c | 46 |
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 */ |
1052 | struct soc_mixer_control { | 1052 | struct 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 */ |
534 | static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = | 526 | static 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 */ |
538 | static const char *twl4030_handsfreer_texts[] = | 530 | static 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 */ |
550 | static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = | 542 | static 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 | ||