aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/extcon/Kconfig2
-rw-r--r--drivers/extcon/extcon-arizona.c93
-rw-r--r--include/linux/mfd/arizona/pdata.h3
3 files changed, 97 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);
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h
index 2f5f08e10b79..f8241753415c 100644
--- a/include/linux/mfd/arizona/pdata.h
+++ b/include/linux/mfd/arizona/pdata.h
@@ -117,6 +117,9 @@ struct arizona_pdata {
117 /** Mic detect debounce level */ 117 /** Mic detect debounce level */
118 int micd_dbtime; 118 int micd_dbtime;
119 119
120 /** Force MICBIAS on for mic detect */
121 bool micd_force_micbias;
122
120 /** Headset polarity configurations */ 123 /** Headset polarity configurations */
121 struct arizona_micd_config *micd_configs; 124 struct arizona_micd_config *micd_configs;
122 int num_micd_configs; 125 int num_micd_configs;