aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2013-01-10 14:38:43 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-02-07 13:19:14 -0500
commitbbbd46e3d7fcdf1c8362bf1c83bcc08a93676cc9 (patch)
treee04d6a9cf0a59f0309d6eaae5a6be146bb5458de /drivers/extcon
parent2e033db5ddf299de2ae568919d78b0258a5a6423 (diff)
extcon: arizona: Use regulated mode for microphone supply when detecting
When starting microphone detection some headsets should be exposed to the fully regulated microphone bias in order to ensure that they behave in an optimal fashion. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/Kconfig2
-rw-r--r--drivers/extcon/extcon-arizona.c93
2 files changed, 94 insertions, 1 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 07122a9ef36e..9377050e5335 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -47,7 +47,7 @@ config EXTCON_MAX8997
47 47
48config EXTCON_ARIZONA 48config EXTCON_ARIZONA
49 tristate "Wolfson Arizona EXTCON support" 49 tristate "Wolfson Arizona EXTCON support"
50 depends on MFD_ARIZONA && INPUT 50 depends on MFD_ARIZONA && INPUT && SND_SOC
51 help 51 help
52 Say Y here to enable support for external accessory detection 52 Say Y here to enable support for external accessory detection
53 with Wolfson Arizona devices. These are audio CODECs with 53 with Wolfson Arizona devices. These are audio CODECs with
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c
index d7e1047ad68e..aa724314677a 100644
--- a/drivers/extcon/extcon-arizona.c
+++ b/drivers/extcon/extcon-arizona.c
@@ -27,6 +27,8 @@
27#include <linux/regulator/consumer.h> 27#include <linux/regulator/consumer.h>
28#include <linux/extcon.h> 28#include <linux/extcon.h>
29 29
30#include <sound/soc.h>
31
30#include <linux/mfd/arizona/core.h> 32#include <linux/mfd/arizona/core.h>
31#include <linux/mfd/arizona/pdata.h> 33#include <linux/mfd/arizona/pdata.h>
32#include <linux/mfd/arizona/registers.h> 34#include <linux/mfd/arizona/registers.h>
@@ -113,6 +115,52 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
113 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode); 115 dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode);
114} 116}
115 117
118static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info)
119{
120 switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) {
121 case 1:
122 return "MICBIAS1";
123 case 2:
124 return "MICBIAS2";
125 case 3:
126 return "MICBIAS3";
127 default:
128 return "MICVDD";
129 }
130}
131
132static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info)
133{
134 struct arizona *arizona = info->arizona;
135 const char *widget = arizona_extcon_get_micbias(info);
136 struct snd_soc_dapm_context *dapm = arizona->dapm;
137 int ret;
138
139 mutex_lock(&dapm->card->dapm_mutex);
140
141 ret = snd_soc_dapm_force_enable_pin(dapm, widget);
142 if (ret != 0)
143 dev_warn(arizona->dev, "Failed to enable %s: %d\n",
144 widget, ret);
145
146 mutex_unlock(&dapm->card->dapm_mutex);
147
148 snd_soc_dapm_sync(dapm);
149
150 if (!arizona->pdata.micd_force_micbias) {
151 mutex_lock(&dapm->card->dapm_mutex);
152
153 ret = snd_soc_dapm_disable_pin(arizona->dapm, widget);
154 if (ret != 0)
155 dev_warn(arizona->dev, "Failed to disable %s: %d\n",
156 widget, ret);
157
158 mutex_unlock(&dapm->card->dapm_mutex);
159
160 snd_soc_dapm_sync(dapm);
161 }
162}
163
116static void arizona_start_mic(struct arizona_extcon_info *info) 164static void arizona_start_mic(struct arizona_extcon_info *info)
117{ 165{
118 struct arizona *arizona = info->arizona; 166 struct arizona *arizona = info->arizona;
@@ -122,6 +170,15 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
122 /* Microphone detection can't use idle mode */ 170 /* Microphone detection can't use idle mode */
123 pm_runtime_get(info->dev); 171 pm_runtime_get(info->dev);
124 172
173 if (info->detecting) {
174 ret = regulator_allow_bypass(info->micvdd, false);
175 if (ret != 0) {
176 dev_err(arizona->dev,
177 "Failed to regulate MICVDD: %d\n",
178 ret);
179 }
180 }
181
125 ret = regulator_enable(info->micvdd); 182 ret = regulator_enable(info->micvdd);
126 if (ret != 0) { 183 if (ret != 0) {
127 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", 184 dev_err(arizona->dev, "Failed to enable MICVDD: %d\n",
@@ -138,6 +195,8 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
138 ARIZONA_ACCESSORY_DETECT_MODE_1, 195 ARIZONA_ACCESSORY_DETECT_MODE_1,
139 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); 196 ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
140 197
198 arizona_extcon_pulse_micbias(info);
199
141 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, 200 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
142 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA, 201 ARIZONA_MICD_ENA, ARIZONA_MICD_ENA,
143 &change); 202 &change);
@@ -150,18 +209,39 @@ static void arizona_start_mic(struct arizona_extcon_info *info)
150static void arizona_stop_mic(struct arizona_extcon_info *info) 209static void arizona_stop_mic(struct arizona_extcon_info *info)
151{ 210{
152 struct arizona *arizona = info->arizona; 211 struct arizona *arizona = info->arizona;
212 const char *widget = arizona_extcon_get_micbias(info);
213 struct snd_soc_dapm_context *dapm = arizona->dapm;
153 bool change; 214 bool change;
215 int ret;
154 216
155 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, 217 regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1,
156 ARIZONA_MICD_ENA, 0, 218 ARIZONA_MICD_ENA, 0,
157 &change); 219 &change);
158 220
221 mutex_lock(&dapm->card->dapm_mutex);
222
223 ret = snd_soc_dapm_disable_pin(dapm, widget);
224 if (ret != 0)
225 dev_warn(arizona->dev,
226 "Failed to disable %s: %d\n",
227 widget, ret);
228
229 mutex_unlock(&dapm->card->dapm_mutex);
230
231 snd_soc_dapm_sync(dapm);
232
159 if (info->micd_reva) { 233 if (info->micd_reva) {
160 regmap_write(arizona->regmap, 0x80, 0x3); 234 regmap_write(arizona->regmap, 0x80, 0x3);
161 regmap_write(arizona->regmap, 0x294, 2); 235 regmap_write(arizona->regmap, 0x294, 2);
162 regmap_write(arizona->regmap, 0x80, 0x0); 236 regmap_write(arizona->regmap, 0x80, 0x0);
163 } 237 }
164 238
239 ret = regulator_allow_bypass(info->micvdd, true);
240 if (ret != 0) {
241 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
242 ret);
243 }
244
165 if (change) { 245 if (change) {
166 regulator_disable(info->micvdd); 246 regulator_disable(info->micvdd);
167 pm_runtime_mark_last_busy(info->dev); 247 pm_runtime_mark_last_busy(info->dev);
@@ -564,6 +644,8 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
564 644
565 info->hpdet_active = true; 645 info->hpdet_active = true;
566 646
647 arizona_extcon_pulse_micbias(info);
648
567 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000); 649 ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
568 if (ret != 0) 650 if (ret != 0)
569 dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); 651 dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
@@ -649,6 +731,13 @@ static irqreturn_t arizona_micdet(int irq, void *data)
649 dev_err(arizona->dev, "Headset report failed: %d\n", 731 dev_err(arizona->dev, "Headset report failed: %d\n",
650 ret); 732 ret);
651 733
734 /* Don't need to regulate for button detection */
735 ret = regulator_allow_bypass(info->micvdd, false);
736 if (ret != 0) {
737 dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n",
738 ret);
739 }
740
652 info->mic = true; 741 info->mic = true;
653 info->detecting = false; 742 info->detecting = false;
654 goto handled; 743 goto handled;
@@ -716,6 +805,7 @@ static irqreturn_t arizona_micdet(int irq, void *data)
716 input_report_key(info->input, 805 input_report_key(info->input,
717 arizona_lvl_to_key[i].report, 0); 806 arizona_lvl_to_key[i].report, 0);
718 input_sync(info->input); 807 input_sync(info->input);
808 arizona_extcon_pulse_micbias(info);
719 } 809 }
720 810
721handled: 811handled:
@@ -817,6 +907,9 @@ static int arizona_extcon_probe(struct platform_device *pdev)
817 int jack_irq_fall, jack_irq_rise; 907 int jack_irq_fall, jack_irq_rise;
818 int ret, mode, i; 908 int ret, mode, i;
819 909
910 if (!arizona->dapm || !arizona->dapm->card)
911 return -EPROBE_DEFER;
912
820 pdata = dev_get_platdata(arizona->dev); 913 pdata = dev_get_platdata(arizona->dev);
821 914
822 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); 915 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);