diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-21 16:57:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-21 16:57:13 -0500 |
commit | 7ed214ac2095f561a94335ca672b6c42a1ea40ff (patch) | |
tree | da41901bff1d0d8d61170bf362384fdc61deb3ab /drivers/extcon | |
parent | 21eaab6d19ed43e82ed39c8deb7f192134fb4a0e (diff) | |
parent | 29e5507ae4ab34397f538f06b7070c81a4e4a2bf (diff) |
Merge tag 'char-misc-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver patches from Greg Kroah-Hartman:
"Here's the big char/misc driver patches for 3.9-rc1.
Nothing major here, just lots of different driver updates (mei,
hyperv, ipack, extcon, vmci, etc.).
All of these have been in the linux-next tree for a while."
* tag 'char-misc-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (209 commits)
w1: w1_therm: Add force-pullup option for "broken" sensors
w1: ds2482: Added 1-Wire pull-up support to the driver
vme: add missing put_device() after device_register() fails
extcon: max8997: Use workqueue to check cable state after completing boot of platform
extcon: max8997: Set default UART/USB path on probe
extcon: max8997: Consolidate duplicate code for checking ADC/CHG cable type
extcon: max8997: Set default of ADC debounce time during initialization
extcon: max8997: Remove duplicate code related to set H/W line path
extcon: max8997: Move defined constant to header file
extcon: max77693: Make max77693_extcon_cable static
extcon: max8997: Remove unreachable code
extcon: max8997: Make max8997_extcon_cable static
extcon: max77693: Remove unnecessary goto statement to improve readability
extcon: max77693: Convert to devm_input_allocate_device()
extcon: gpio: Rename filename of extcon-gpio.c according to kernel naming style
CREDITS: update email and address of Harald Hoyer
extcon: arizona: Use MICDET for final microphone identification
extcon: arizona: Always take the first HPDET reading as the final one
extcon: arizona: Clear _trig_sts bits after jack detection
extcon: arizona: Don't HPDET magic when headphones are enabled
...
Diffstat (limited to 'drivers/extcon')
-rw-r--r-- | drivers/extcon/Kconfig | 4 | ||||
-rw-r--r-- | drivers/extcon/extcon-arizona.c | 810 | ||||
-rw-r--r-- | drivers/extcon/extcon-gpio.c | 2 | ||||
-rw-r--r-- | drivers/extcon/extcon-max77693.c | 981 | ||||
-rw-r--r-- | drivers/extcon/extcon-max8997.c | 734 |
5 files changed, 1972 insertions, 559 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 07122a9ef36e..5168a1324a65 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig | |||
@@ -29,7 +29,7 @@ config EXTCON_ADC_JACK | |||
29 | 29 | ||
30 | config EXTCON_MAX77693 | 30 | config EXTCON_MAX77693 |
31 | tristate "MAX77693 EXTCON Support" | 31 | tristate "MAX77693 EXTCON Support" |
32 | depends on MFD_MAX77693 | 32 | depends on MFD_MAX77693 && INPUT |
33 | select IRQ_DOMAIN | 33 | select IRQ_DOMAIN |
34 | select REGMAP_I2C | 34 | select REGMAP_I2C |
35 | help | 35 | help |
@@ -47,7 +47,7 @@ config EXTCON_MAX8997 | |||
47 | 47 | ||
48 | config EXTCON_ARIZONA | 48 | config 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 414aed50b1bc..dc357a4051f6 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c | |||
@@ -27,12 +27,18 @@ | |||
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> |
33 | 35 | ||
34 | #define ARIZONA_NUM_BUTTONS 6 | 36 | #define ARIZONA_NUM_BUTTONS 6 |
35 | 37 | ||
38 | #define ARIZONA_ACCDET_MODE_MIC 0 | ||
39 | #define ARIZONA_ACCDET_MODE_HPL 1 | ||
40 | #define ARIZONA_ACCDET_MODE_HPR 2 | ||
41 | |||
36 | struct arizona_extcon_info { | 42 | struct arizona_extcon_info { |
37 | struct device *dev; | 43 | struct device *dev; |
38 | struct arizona *arizona; | 44 | struct arizona *arizona; |
@@ -45,17 +51,28 @@ struct arizona_extcon_info { | |||
45 | int micd_num_modes; | 51 | int micd_num_modes; |
46 | 52 | ||
47 | bool micd_reva; | 53 | bool micd_reva; |
54 | bool micd_clamp; | ||
55 | |||
56 | struct delayed_work hpdet_work; | ||
57 | |||
58 | bool hpdet_active; | ||
59 | bool hpdet_done; | ||
60 | |||
61 | int num_hpdet_res; | ||
62 | unsigned int hpdet_res[3]; | ||
48 | 63 | ||
49 | bool mic; | 64 | bool mic; |
50 | bool detecting; | 65 | bool detecting; |
51 | int jack_flips; | 66 | int jack_flips; |
52 | 67 | ||
68 | int hpdet_ip; | ||
69 | |||
53 | struct extcon_dev edev; | 70 | struct extcon_dev edev; |
54 | }; | 71 | }; |
55 | 72 | ||
56 | static const struct arizona_micd_config micd_default_modes[] = { | 73 | static const struct arizona_micd_config micd_default_modes[] = { |
57 | { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 }, | ||
58 | { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 }, | 74 | { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 }, |
75 | { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 }, | ||
59 | }; | 76 | }; |
60 | 77 | ||
61 | static struct { | 78 | static struct { |
@@ -73,11 +90,13 @@ static struct { | |||
73 | #define ARIZONA_CABLE_MECHANICAL 0 | 90 | #define ARIZONA_CABLE_MECHANICAL 0 |
74 | #define ARIZONA_CABLE_MICROPHONE 1 | 91 | #define ARIZONA_CABLE_MICROPHONE 1 |
75 | #define ARIZONA_CABLE_HEADPHONE 2 | 92 | #define ARIZONA_CABLE_HEADPHONE 2 |
93 | #define ARIZONA_CABLE_LINEOUT 3 | ||
76 | 94 | ||
77 | static const char *arizona_cable[] = { | 95 | static const char *arizona_cable[] = { |
78 | "Mechanical", | 96 | "Mechanical", |
79 | "Microphone", | 97 | "Microphone", |
80 | "Headphone", | 98 | "Headphone", |
99 | "Line-out", | ||
81 | NULL, | 100 | NULL, |
82 | }; | 101 | }; |
83 | 102 | ||
@@ -85,8 +104,9 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) | |||
85 | { | 104 | { |
86 | struct arizona *arizona = info->arizona; | 105 | struct arizona *arizona = info->arizona; |
87 | 106 | ||
88 | gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, | 107 | if (arizona->pdata.micd_pol_gpio > 0) |
89 | info->micd_modes[mode].gpio); | 108 | gpio_set_value_cansleep(arizona->pdata.micd_pol_gpio, |
109 | info->micd_modes[mode].gpio); | ||
90 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, | 110 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, |
91 | ARIZONA_MICD_BIAS_SRC_MASK, | 111 | ARIZONA_MICD_BIAS_SRC_MASK, |
92 | info->micd_modes[mode].bias); | 112 | info->micd_modes[mode].bias); |
@@ -98,19 +118,70 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) | |||
98 | dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode); | 118 | dev_dbg(arizona->dev, "Set jack polarity to %d\n", mode); |
99 | } | 119 | } |
100 | 120 | ||
121 | static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) | ||
122 | { | ||
123 | switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) { | ||
124 | case 1: | ||
125 | return "MICBIAS1"; | ||
126 | case 2: | ||
127 | return "MICBIAS2"; | ||
128 | case 3: | ||
129 | return "MICBIAS3"; | ||
130 | default: | ||
131 | return "MICVDD"; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) | ||
136 | { | ||
137 | struct arizona *arizona = info->arizona; | ||
138 | const char *widget = arizona_extcon_get_micbias(info); | ||
139 | struct snd_soc_dapm_context *dapm = arizona->dapm; | ||
140 | int ret; | ||
141 | |||
142 | mutex_lock(&dapm->card->dapm_mutex); | ||
143 | |||
144 | ret = snd_soc_dapm_force_enable_pin(dapm, widget); | ||
145 | if (ret != 0) | ||
146 | dev_warn(arizona->dev, "Failed to enable %s: %d\n", | ||
147 | widget, ret); | ||
148 | |||
149 | mutex_unlock(&dapm->card->dapm_mutex); | ||
150 | |||
151 | snd_soc_dapm_sync(dapm); | ||
152 | |||
153 | if (!arizona->pdata.micd_force_micbias) { | ||
154 | mutex_lock(&dapm->card->dapm_mutex); | ||
155 | |||
156 | ret = snd_soc_dapm_disable_pin(arizona->dapm, widget); | ||
157 | if (ret != 0) | ||
158 | dev_warn(arizona->dev, "Failed to disable %s: %d\n", | ||
159 | widget, ret); | ||
160 | |||
161 | mutex_unlock(&dapm->card->dapm_mutex); | ||
162 | |||
163 | snd_soc_dapm_sync(dapm); | ||
164 | } | ||
165 | } | ||
166 | |||
101 | static void arizona_start_mic(struct arizona_extcon_info *info) | 167 | static void arizona_start_mic(struct arizona_extcon_info *info) |
102 | { | 168 | { |
103 | struct arizona *arizona = info->arizona; | 169 | struct arizona *arizona = info->arizona; |
104 | bool change; | 170 | bool change; |
105 | int ret; | 171 | int ret; |
106 | 172 | ||
107 | info->detecting = true; | ||
108 | info->mic = false; | ||
109 | info->jack_flips = 0; | ||
110 | |||
111 | /* Microphone detection can't use idle mode */ | 173 | /* Microphone detection can't use idle mode */ |
112 | pm_runtime_get(info->dev); | 174 | pm_runtime_get(info->dev); |
113 | 175 | ||
176 | if (info->detecting) { | ||
177 | ret = regulator_allow_bypass(info->micvdd, false); | ||
178 | if (ret != 0) { | ||
179 | dev_err(arizona->dev, | ||
180 | "Failed to regulate MICVDD: %d\n", | ||
181 | ret); | ||
182 | } | ||
183 | } | ||
184 | |||
114 | ret = regulator_enable(info->micvdd); | 185 | ret = regulator_enable(info->micvdd); |
115 | if (ret != 0) { | 186 | if (ret != 0) { |
116 | dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", | 187 | dev_err(arizona->dev, "Failed to enable MICVDD: %d\n", |
@@ -123,6 +194,12 @@ static void arizona_start_mic(struct arizona_extcon_info *info) | |||
123 | regmap_write(arizona->regmap, 0x80, 0x0); | 194 | regmap_write(arizona->regmap, 0x80, 0x0); |
124 | } | 195 | } |
125 | 196 | ||
197 | regmap_update_bits(arizona->regmap, | ||
198 | ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
199 | ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); | ||
200 | |||
201 | arizona_extcon_pulse_micbias(info); | ||
202 | |||
126 | regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, | 203 | regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
127 | ARIZONA_MICD_ENA, ARIZONA_MICD_ENA, | 204 | ARIZONA_MICD_ENA, ARIZONA_MICD_ENA, |
128 | &change); | 205 | &change); |
@@ -135,18 +212,39 @@ static void arizona_start_mic(struct arizona_extcon_info *info) | |||
135 | static void arizona_stop_mic(struct arizona_extcon_info *info) | 212 | static void arizona_stop_mic(struct arizona_extcon_info *info) |
136 | { | 213 | { |
137 | struct arizona *arizona = info->arizona; | 214 | struct arizona *arizona = info->arizona; |
215 | const char *widget = arizona_extcon_get_micbias(info); | ||
216 | struct snd_soc_dapm_context *dapm = arizona->dapm; | ||
138 | bool change; | 217 | bool change; |
218 | int ret; | ||
139 | 219 | ||
140 | regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, | 220 | regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, |
141 | ARIZONA_MICD_ENA, 0, | 221 | ARIZONA_MICD_ENA, 0, |
142 | &change); | 222 | &change); |
143 | 223 | ||
224 | mutex_lock(&dapm->card->dapm_mutex); | ||
225 | |||
226 | ret = snd_soc_dapm_disable_pin(dapm, widget); | ||
227 | if (ret != 0) | ||
228 | dev_warn(arizona->dev, | ||
229 | "Failed to disable %s: %d\n", | ||
230 | widget, ret); | ||
231 | |||
232 | mutex_unlock(&dapm->card->dapm_mutex); | ||
233 | |||
234 | snd_soc_dapm_sync(dapm); | ||
235 | |||
144 | if (info->micd_reva) { | 236 | if (info->micd_reva) { |
145 | regmap_write(arizona->regmap, 0x80, 0x3); | 237 | regmap_write(arizona->regmap, 0x80, 0x3); |
146 | regmap_write(arizona->regmap, 0x294, 2); | 238 | regmap_write(arizona->regmap, 0x294, 2); |
147 | regmap_write(arizona->regmap, 0x80, 0x0); | 239 | regmap_write(arizona->regmap, 0x80, 0x0); |
148 | } | 240 | } |
149 | 241 | ||
242 | ret = regulator_allow_bypass(info->micvdd, true); | ||
243 | if (ret != 0) { | ||
244 | dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", | ||
245 | ret); | ||
246 | } | ||
247 | |||
150 | if (change) { | 248 | if (change) { |
151 | regulator_disable(info->micvdd); | 249 | regulator_disable(info->micvdd); |
152 | pm_runtime_mark_last_busy(info->dev); | 250 | pm_runtime_mark_last_busy(info->dev); |
@@ -154,6 +252,478 @@ static void arizona_stop_mic(struct arizona_extcon_info *info) | |||
154 | } | 252 | } |
155 | } | 253 | } |
156 | 254 | ||
255 | static struct { | ||
256 | unsigned int factor_a; | ||
257 | unsigned int factor_b; | ||
258 | } arizona_hpdet_b_ranges[] = { | ||
259 | { 5528, 362464 }, | ||
260 | { 11084, 6186851 }, | ||
261 | { 11065, 65460395 }, | ||
262 | }; | ||
263 | |||
264 | static struct { | ||
265 | int min; | ||
266 | int max; | ||
267 | } arizona_hpdet_c_ranges[] = { | ||
268 | { 0, 30 }, | ||
269 | { 8, 100 }, | ||
270 | { 100, 1000 }, | ||
271 | { 1000, 10000 }, | ||
272 | }; | ||
273 | |||
274 | static int arizona_hpdet_read(struct arizona_extcon_info *info) | ||
275 | { | ||
276 | struct arizona *arizona = info->arizona; | ||
277 | unsigned int val, range; | ||
278 | int ret; | ||
279 | |||
280 | ret = regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_2, &val); | ||
281 | if (ret != 0) { | ||
282 | dev_err(arizona->dev, "Failed to read HPDET status: %d\n", | ||
283 | ret); | ||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | switch (info->hpdet_ip) { | ||
288 | case 0: | ||
289 | if (!(val & ARIZONA_HP_DONE)) { | ||
290 | dev_err(arizona->dev, "HPDET did not complete: %x\n", | ||
291 | val); | ||
292 | return -EAGAIN; | ||
293 | } | ||
294 | |||
295 | val &= ARIZONA_HP_LVL_MASK; | ||
296 | break; | ||
297 | |||
298 | case 1: | ||
299 | if (!(val & ARIZONA_HP_DONE_B)) { | ||
300 | dev_err(arizona->dev, "HPDET did not complete: %x\n", | ||
301 | val); | ||
302 | return -EAGAIN; | ||
303 | } | ||
304 | |||
305 | ret = regmap_read(arizona->regmap, ARIZONA_HP_DACVAL, &val); | ||
306 | if (ret != 0) { | ||
307 | dev_err(arizona->dev, "Failed to read HP value: %d\n", | ||
308 | ret); | ||
309 | return -EAGAIN; | ||
310 | } | ||
311 | |||
312 | regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, | ||
313 | &range); | ||
314 | range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK) | ||
315 | >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT; | ||
316 | |||
317 | if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 && | ||
318 | (val < 100 || val > 0x3fb)) { | ||
319 | range++; | ||
320 | dev_dbg(arizona->dev, "Moving to HPDET range %d\n", | ||
321 | range); | ||
322 | regmap_update_bits(arizona->regmap, | ||
323 | ARIZONA_HEADPHONE_DETECT_1, | ||
324 | ARIZONA_HP_IMPEDANCE_RANGE_MASK, | ||
325 | range << | ||
326 | ARIZONA_HP_IMPEDANCE_RANGE_SHIFT); | ||
327 | return -EAGAIN; | ||
328 | } | ||
329 | |||
330 | /* If we go out of range report top of range */ | ||
331 | if (val < 100 || val > 0x3fb) { | ||
332 | dev_dbg(arizona->dev, "Measurement out of range\n"); | ||
333 | return 10000; | ||
334 | } | ||
335 | |||
336 | dev_dbg(arizona->dev, "HPDET read %d in range %d\n", | ||
337 | val, range); | ||
338 | |||
339 | val = arizona_hpdet_b_ranges[range].factor_b | ||
340 | / ((val * 100) - | ||
341 | arizona_hpdet_b_ranges[range].factor_a); | ||
342 | break; | ||
343 | |||
344 | default: | ||
345 | dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n", | ||
346 | info->hpdet_ip); | ||
347 | case 2: | ||
348 | if (!(val & ARIZONA_HP_DONE_B)) { | ||
349 | dev_err(arizona->dev, "HPDET did not complete: %x\n", | ||
350 | val); | ||
351 | return -EAGAIN; | ||
352 | } | ||
353 | |||
354 | val &= ARIZONA_HP_LVL_B_MASK; | ||
355 | |||
356 | regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, | ||
357 | &range); | ||
358 | range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK) | ||
359 | >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT; | ||
360 | |||
361 | /* Skip up or down a range? */ | ||
362 | if (range && (val < arizona_hpdet_c_ranges[range].min)) { | ||
363 | range--; | ||
364 | dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n", | ||
365 | arizona_hpdet_c_ranges[range].min, | ||
366 | arizona_hpdet_c_ranges[range].max); | ||
367 | regmap_update_bits(arizona->regmap, | ||
368 | ARIZONA_HEADPHONE_DETECT_1, | ||
369 | ARIZONA_HP_IMPEDANCE_RANGE_MASK, | ||
370 | range << | ||
371 | ARIZONA_HP_IMPEDANCE_RANGE_SHIFT); | ||
372 | return -EAGAIN; | ||
373 | } | ||
374 | |||
375 | if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 && | ||
376 | (val >= arizona_hpdet_c_ranges[range].max)) { | ||
377 | range++; | ||
378 | dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n", | ||
379 | arizona_hpdet_c_ranges[range].min, | ||
380 | arizona_hpdet_c_ranges[range].max); | ||
381 | regmap_update_bits(arizona->regmap, | ||
382 | ARIZONA_HEADPHONE_DETECT_1, | ||
383 | ARIZONA_HP_IMPEDANCE_RANGE_MASK, | ||
384 | range << | ||
385 | ARIZONA_HP_IMPEDANCE_RANGE_SHIFT); | ||
386 | return -EAGAIN; | ||
387 | } | ||
388 | } | ||
389 | |||
390 | dev_dbg(arizona->dev, "HP impedance %d ohms\n", val); | ||
391 | return val; | ||
392 | } | ||
393 | |||
394 | static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading) | ||
395 | { | ||
396 | struct arizona *arizona = info->arizona; | ||
397 | int id_gpio = arizona->pdata.hpdet_id_gpio; | ||
398 | |||
399 | /* | ||
400 | * If we're using HPDET for accessory identification we need | ||
401 | * to take multiple measurements, step through them in sequence. | ||
402 | */ | ||
403 | if (arizona->pdata.hpdet_acc_id) { | ||
404 | info->hpdet_res[info->num_hpdet_res++] = *reading; | ||
405 | |||
406 | /* | ||
407 | * If the impedence is too high don't measure the | ||
408 | * second ground. | ||
409 | */ | ||
410 | if (info->num_hpdet_res == 1 && *reading >= 45) { | ||
411 | dev_dbg(arizona->dev, "Skipping ground flip\n"); | ||
412 | info->hpdet_res[info->num_hpdet_res++] = *reading; | ||
413 | } | ||
414 | |||
415 | if (info->num_hpdet_res == 1) { | ||
416 | dev_dbg(arizona->dev, "Flipping ground\n"); | ||
417 | |||
418 | regmap_update_bits(arizona->regmap, | ||
419 | ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
420 | ARIZONA_ACCDET_SRC, | ||
421 | ~info->micd_modes[0].src); | ||
422 | |||
423 | regmap_update_bits(arizona->regmap, | ||
424 | ARIZONA_HEADPHONE_DETECT_1, | ||
425 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); | ||
426 | return -EAGAIN; | ||
427 | } | ||
428 | |||
429 | /* Only check the mic directly if we didn't already ID it */ | ||
430 | if (id_gpio && info->num_hpdet_res == 2 && | ||
431 | !((info->hpdet_res[0] > info->hpdet_res[1] * 2))) { | ||
432 | dev_dbg(arizona->dev, "Measuring mic\n"); | ||
433 | |||
434 | regmap_update_bits(arizona->regmap, | ||
435 | ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
436 | ARIZONA_ACCDET_MODE_MASK | | ||
437 | ARIZONA_ACCDET_SRC, | ||
438 | ARIZONA_ACCDET_MODE_HPR | | ||
439 | info->micd_modes[0].src); | ||
440 | |||
441 | gpio_set_value_cansleep(id_gpio, 1); | ||
442 | |||
443 | regmap_update_bits(arizona->regmap, | ||
444 | ARIZONA_HEADPHONE_DETECT_1, | ||
445 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); | ||
446 | return -EAGAIN; | ||
447 | } | ||
448 | |||
449 | /* OK, got both. Now, compare... */ | ||
450 | dev_dbg(arizona->dev, "HPDET measured %d %d %d\n", | ||
451 | info->hpdet_res[0], info->hpdet_res[1], | ||
452 | info->hpdet_res[2]); | ||
453 | |||
454 | |||
455 | /* Take the headphone impedance for the main report */ | ||
456 | *reading = info->hpdet_res[0]; | ||
457 | |||
458 | /* | ||
459 | * Either the two grounds measure differently or we | ||
460 | * measure the mic as high impedance. | ||
461 | */ | ||
462 | if ((info->hpdet_res[0] > info->hpdet_res[1] * 2) || | ||
463 | (id_gpio && info->hpdet_res[2] > 10)) { | ||
464 | dev_dbg(arizona->dev, "Detected mic\n"); | ||
465 | info->mic = true; | ||
466 | info->detecting = true; | ||
467 | } else { | ||
468 | dev_dbg(arizona->dev, "Detected headphone\n"); | ||
469 | } | ||
470 | |||
471 | /* Make sure everything is reset back to the real polarity */ | ||
472 | regmap_update_bits(arizona->regmap, | ||
473 | ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
474 | ARIZONA_ACCDET_SRC, | ||
475 | info->micd_modes[0].src); | ||
476 | } | ||
477 | |||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | static irqreturn_t arizona_hpdet_irq(int irq, void *data) | ||
482 | { | ||
483 | struct arizona_extcon_info *info = data; | ||
484 | struct arizona *arizona = info->arizona; | ||
485 | int id_gpio = arizona->pdata.hpdet_id_gpio; | ||
486 | int report = ARIZONA_CABLE_HEADPHONE; | ||
487 | unsigned int val; | ||
488 | int ret, reading; | ||
489 | |||
490 | mutex_lock(&info->lock); | ||
491 | |||
492 | /* If we got a spurious IRQ for some reason then ignore it */ | ||
493 | if (!info->hpdet_active) { | ||
494 | dev_warn(arizona->dev, "Spurious HPDET IRQ\n"); | ||
495 | mutex_unlock(&info->lock); | ||
496 | return IRQ_NONE; | ||
497 | } | ||
498 | |||
499 | /* If the cable was removed while measuring ignore the result */ | ||
500 | ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL); | ||
501 | if (ret < 0) { | ||
502 | dev_err(arizona->dev, "Failed to check cable state: %d\n", | ||
503 | ret); | ||
504 | goto out; | ||
505 | } else if (!ret) { | ||
506 | dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n"); | ||
507 | goto done; | ||
508 | } | ||
509 | |||
510 | ret = arizona_hpdet_read(info); | ||
511 | if (ret == -EAGAIN) { | ||
512 | goto out; | ||
513 | } else if (ret < 0) { | ||
514 | goto done; | ||
515 | } | ||
516 | reading = ret; | ||
517 | |||
518 | /* Reset back to starting range */ | ||
519 | regmap_update_bits(arizona->regmap, | ||
520 | ARIZONA_HEADPHONE_DETECT_1, | ||
521 | ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL, | ||
522 | 0); | ||
523 | |||
524 | ret = arizona_hpdet_do_id(info, &reading); | ||
525 | if (ret == -EAGAIN) { | ||
526 | goto out; | ||
527 | } else if (ret < 0) { | ||
528 | goto done; | ||
529 | } | ||
530 | |||
531 | /* Report high impedence cables as line outputs */ | ||
532 | if (reading >= 5000) | ||
533 | report = ARIZONA_CABLE_LINEOUT; | ||
534 | else | ||
535 | report = ARIZONA_CABLE_HEADPHONE; | ||
536 | |||
537 | ret = extcon_set_cable_state_(&info->edev, report, true); | ||
538 | if (ret != 0) | ||
539 | dev_err(arizona->dev, "Failed to report HP/line: %d\n", | ||
540 | ret); | ||
541 | |||
542 | mutex_lock(&arizona->dapm->card->dapm_mutex); | ||
543 | |||
544 | ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); | ||
545 | if (ret != 0) { | ||
546 | dev_err(arizona->dev, "Failed to read output enables: %d\n", | ||
547 | ret); | ||
548 | val = 0; | ||
549 | } | ||
550 | |||
551 | if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { | ||
552 | ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0); | ||
553 | if (ret != 0) | ||
554 | dev_warn(arizona->dev, "Failed to undo magic: %d\n", | ||
555 | ret); | ||
556 | |||
557 | ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0); | ||
558 | if (ret != 0) | ||
559 | dev_warn(arizona->dev, "Failed to undo magic: %d\n", | ||
560 | ret); | ||
561 | } | ||
562 | |||
563 | mutex_unlock(&arizona->dapm->card->dapm_mutex); | ||
564 | |||
565 | done: | ||
566 | if (id_gpio) | ||
567 | gpio_set_value_cansleep(id_gpio, 0); | ||
568 | |||
569 | /* Revert back to MICDET mode */ | ||
570 | regmap_update_bits(arizona->regmap, | ||
571 | ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
572 | ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); | ||
573 | |||
574 | /* If we have a mic then reenable MICDET */ | ||
575 | if (info->mic) | ||
576 | arizona_start_mic(info); | ||
577 | |||
578 | if (info->hpdet_active) { | ||
579 | pm_runtime_put_autosuspend(info->dev); | ||
580 | info->hpdet_active = false; | ||
581 | } | ||
582 | |||
583 | info->hpdet_done = true; | ||
584 | |||
585 | out: | ||
586 | mutex_unlock(&info->lock); | ||
587 | |||
588 | return IRQ_HANDLED; | ||
589 | } | ||
590 | |||
591 | static void arizona_identify_headphone(struct arizona_extcon_info *info) | ||
592 | { | ||
593 | struct arizona *arizona = info->arizona; | ||
594 | int ret; | ||
595 | |||
596 | if (info->hpdet_done) | ||
597 | return; | ||
598 | |||
599 | dev_dbg(arizona->dev, "Starting HPDET\n"); | ||
600 | |||
601 | /* Make sure we keep the device enabled during the measurement */ | ||
602 | pm_runtime_get(info->dev); | ||
603 | |||
604 | info->hpdet_active = true; | ||
605 | |||
606 | if (info->mic) | ||
607 | arizona_stop_mic(info); | ||
608 | |||
609 | ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000); | ||
610 | if (ret != 0) | ||
611 | dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); | ||
612 | |||
613 | ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000); | ||
614 | if (ret != 0) | ||
615 | dev_warn(arizona->dev, "Failed to do magic: %d\n", ret); | ||
616 | |||
617 | ret = regmap_update_bits(arizona->regmap, | ||
618 | ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
619 | ARIZONA_ACCDET_MODE_MASK, | ||
620 | ARIZONA_ACCDET_MODE_HPL); | ||
621 | if (ret != 0) { | ||
622 | dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret); | ||
623 | goto err; | ||
624 | } | ||
625 | |||
626 | ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, | ||
627 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); | ||
628 | if (ret != 0) { | ||
629 | dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", | ||
630 | ret); | ||
631 | goto err; | ||
632 | } | ||
633 | |||
634 | return; | ||
635 | |||
636 | err: | ||
637 | regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
638 | ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); | ||
639 | |||
640 | /* Just report headphone */ | ||
641 | ret = extcon_update_state(&info->edev, | ||
642 | 1 << ARIZONA_CABLE_HEADPHONE, | ||
643 | 1 << ARIZONA_CABLE_HEADPHONE); | ||
644 | if (ret != 0) | ||
645 | dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); | ||
646 | |||
647 | if (info->mic) | ||
648 | arizona_start_mic(info); | ||
649 | |||
650 | info->hpdet_active = false; | ||
651 | } | ||
652 | |||
653 | static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) | ||
654 | { | ||
655 | struct arizona *arizona = info->arizona; | ||
656 | unsigned int val; | ||
657 | int ret; | ||
658 | |||
659 | dev_dbg(arizona->dev, "Starting identification via HPDET\n"); | ||
660 | |||
661 | /* Make sure we keep the device enabled during the measurement */ | ||
662 | pm_runtime_get_sync(info->dev); | ||
663 | |||
664 | info->hpdet_active = true; | ||
665 | |||
666 | arizona_extcon_pulse_micbias(info); | ||
667 | |||
668 | mutex_lock(&arizona->dapm->card->dapm_mutex); | ||
669 | |||
670 | ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val); | ||
671 | if (ret != 0) { | ||
672 | dev_err(arizona->dev, "Failed to read output enables: %d\n", | ||
673 | ret); | ||
674 | val = 0; | ||
675 | } | ||
676 | |||
677 | if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) { | ||
678 | ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, | ||
679 | 0x4000); | ||
680 | if (ret != 0) | ||
681 | dev_warn(arizona->dev, "Failed to do magic: %d\n", | ||
682 | ret); | ||
683 | |||
684 | ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, | ||
685 | 0x4000); | ||
686 | if (ret != 0) | ||
687 | dev_warn(arizona->dev, "Failed to do magic: %d\n", | ||
688 | ret); | ||
689 | } | ||
690 | |||
691 | mutex_unlock(&arizona->dapm->card->dapm_mutex); | ||
692 | |||
693 | ret = regmap_update_bits(arizona->regmap, | ||
694 | ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
695 | ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK, | ||
696 | info->micd_modes[0].src | | ||
697 | ARIZONA_ACCDET_MODE_HPL); | ||
698 | if (ret != 0) { | ||
699 | dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret); | ||
700 | goto err; | ||
701 | } | ||
702 | |||
703 | ret = regmap_update_bits(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, | ||
704 | ARIZONA_HP_POLL, ARIZONA_HP_POLL); | ||
705 | if (ret != 0) { | ||
706 | dev_err(arizona->dev, "Can't start HPDETL measurement: %d\n", | ||
707 | ret); | ||
708 | goto err; | ||
709 | } | ||
710 | |||
711 | return; | ||
712 | |||
713 | err: | ||
714 | regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, | ||
715 | ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); | ||
716 | |||
717 | /* Just report headphone */ | ||
718 | ret = extcon_update_state(&info->edev, | ||
719 | 1 << ARIZONA_CABLE_HEADPHONE, | ||
720 | 1 << ARIZONA_CABLE_HEADPHONE); | ||
721 | if (ret != 0) | ||
722 | dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); | ||
723 | |||
724 | info->hpdet_active = false; | ||
725 | } | ||
726 | |||
157 | static irqreturn_t arizona_micdet(int irq, void *data) | 727 | static irqreturn_t arizona_micdet(int irq, void *data) |
158 | { | 728 | { |
159 | struct arizona_extcon_info *info = data; | 729 | struct arizona_extcon_info *info = data; |
@@ -187,16 +757,23 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
187 | 757 | ||
188 | /* If we got a high impedence we should have a headset, report it. */ | 758 | /* If we got a high impedence we should have a headset, report it. */ |
189 | if (info->detecting && (val & 0x400)) { | 759 | if (info->detecting && (val & 0x400)) { |
760 | arizona_identify_headphone(info); | ||
761 | |||
190 | ret = extcon_update_state(&info->edev, | 762 | ret = extcon_update_state(&info->edev, |
191 | 1 << ARIZONA_CABLE_MICROPHONE | | 763 | 1 << ARIZONA_CABLE_MICROPHONE, |
192 | 1 << ARIZONA_CABLE_HEADPHONE, | 764 | 1 << ARIZONA_CABLE_MICROPHONE); |
193 | 1 << ARIZONA_CABLE_MICROPHONE | | ||
194 | 1 << ARIZONA_CABLE_HEADPHONE); | ||
195 | 765 | ||
196 | if (ret != 0) | 766 | if (ret != 0) |
197 | dev_err(arizona->dev, "Headset report failed: %d\n", | 767 | dev_err(arizona->dev, "Headset report failed: %d\n", |
198 | ret); | 768 | ret); |
199 | 769 | ||
770 | /* Don't need to regulate for button detection */ | ||
771 | ret = regulator_allow_bypass(info->micvdd, false); | ||
772 | if (ret != 0) { | ||
773 | dev_err(arizona->dev, "Failed to bypass MICVDD: %d\n", | ||
774 | ret); | ||
775 | } | ||
776 | |||
200 | info->mic = true; | 777 | info->mic = true; |
201 | info->detecting = false; | 778 | info->detecting = false; |
202 | goto handled; | 779 | goto handled; |
@@ -209,20 +786,13 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
209 | * impedence then give up and report headphones. | 786 | * impedence then give up and report headphones. |
210 | */ | 787 | */ |
211 | if (info->detecting && (val & 0x3f8)) { | 788 | if (info->detecting && (val & 0x3f8)) { |
212 | info->jack_flips++; | ||
213 | |||
214 | if (info->jack_flips >= info->micd_num_modes) { | 789 | if (info->jack_flips >= info->micd_num_modes) { |
215 | dev_dbg(arizona->dev, "Detected headphone\n"); | 790 | dev_dbg(arizona->dev, "Detected HP/line\n"); |
791 | arizona_identify_headphone(info); | ||
792 | |||
216 | info->detecting = false; | 793 | info->detecting = false; |
217 | arizona_stop_mic(info); | ||
218 | 794 | ||
219 | ret = extcon_set_cable_state_(&info->edev, | 795 | arizona_stop_mic(info); |
220 | ARIZONA_CABLE_HEADPHONE, | ||
221 | true); | ||
222 | if (ret != 0) | ||
223 | dev_err(arizona->dev, | ||
224 | "Headphone report failed: %d\n", | ||
225 | ret); | ||
226 | } else { | 796 | } else { |
227 | info->micd_mode++; | 797 | info->micd_mode++; |
228 | if (info->micd_mode == info->micd_num_modes) | 798 | if (info->micd_mode == info->micd_num_modes) |
@@ -258,13 +828,7 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
258 | info->detecting = false; | 828 | info->detecting = false; |
259 | arizona_stop_mic(info); | 829 | arizona_stop_mic(info); |
260 | 830 | ||
261 | ret = extcon_set_cable_state_(&info->edev, | 831 | arizona_identify_headphone(info); |
262 | ARIZONA_CABLE_HEADPHONE, | ||
263 | true); | ||
264 | if (ret != 0) | ||
265 | dev_err(arizona->dev, | ||
266 | "Headphone report failed: %d\n", | ||
267 | ret); | ||
268 | } else { | 832 | } else { |
269 | dev_warn(arizona->dev, "Button with no mic: %x\n", | 833 | dev_warn(arizona->dev, "Button with no mic: %x\n", |
270 | val); | 834 | val); |
@@ -275,6 +839,7 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
275 | input_report_key(info->input, | 839 | input_report_key(info->input, |
276 | arizona_lvl_to_key[i].report, 0); | 840 | arizona_lvl_to_key[i].report, 0); |
277 | input_sync(info->input); | 841 | input_sync(info->input); |
842 | arizona_extcon_pulse_micbias(info); | ||
278 | } | 843 | } |
279 | 844 | ||
280 | handled: | 845 | handled: |
@@ -284,17 +849,38 @@ handled: | |||
284 | return IRQ_HANDLED; | 849 | return IRQ_HANDLED; |
285 | } | 850 | } |
286 | 851 | ||
852 | static void arizona_hpdet_work(struct work_struct *work) | ||
853 | { | ||
854 | struct arizona_extcon_info *info = container_of(work, | ||
855 | struct arizona_extcon_info, | ||
856 | hpdet_work.work); | ||
857 | |||
858 | mutex_lock(&info->lock); | ||
859 | arizona_start_hpdet_acc_id(info); | ||
860 | mutex_unlock(&info->lock); | ||
861 | } | ||
862 | |||
287 | static irqreturn_t arizona_jackdet(int irq, void *data) | 863 | static irqreturn_t arizona_jackdet(int irq, void *data) |
288 | { | 864 | { |
289 | struct arizona_extcon_info *info = data; | 865 | struct arizona_extcon_info *info = data; |
290 | struct arizona *arizona = info->arizona; | 866 | struct arizona *arizona = info->arizona; |
291 | unsigned int val; | 867 | unsigned int val, present, mask; |
292 | int ret, i; | 868 | int ret, i; |
293 | 869 | ||
294 | pm_runtime_get_sync(info->dev); | 870 | pm_runtime_get_sync(info->dev); |
295 | 871 | ||
872 | cancel_delayed_work_sync(&info->hpdet_work); | ||
873 | |||
296 | mutex_lock(&info->lock); | 874 | mutex_lock(&info->lock); |
297 | 875 | ||
876 | if (arizona->pdata.jd_gpio5) { | ||
877 | mask = ARIZONA_MICD_CLAMP_STS; | ||
878 | present = 0; | ||
879 | } else { | ||
880 | mask = ARIZONA_JD1_STS; | ||
881 | present = ARIZONA_JD1_STS; | ||
882 | } | ||
883 | |||
298 | ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); | 884 | ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); |
299 | if (ret != 0) { | 885 | if (ret != 0) { |
300 | dev_err(arizona->dev, "Failed to read jackdet status: %d\n", | 886 | dev_err(arizona->dev, "Failed to read jackdet status: %d\n", |
@@ -304,7 +890,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
304 | return IRQ_NONE; | 890 | return IRQ_NONE; |
305 | } | 891 | } |
306 | 892 | ||
307 | if (val & ARIZONA_JD1_STS) { | 893 | if ((val & mask) == present) { |
308 | dev_dbg(arizona->dev, "Detected jack\n"); | 894 | dev_dbg(arizona->dev, "Detected jack\n"); |
309 | ret = extcon_set_cable_state_(&info->edev, | 895 | ret = extcon_set_cable_state_(&info->edev, |
310 | ARIZONA_CABLE_MECHANICAL, true); | 896 | ARIZONA_CABLE_MECHANICAL, true); |
@@ -313,12 +899,31 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
313 | dev_err(arizona->dev, "Mechanical report failed: %d\n", | 899 | dev_err(arizona->dev, "Mechanical report failed: %d\n", |
314 | ret); | 900 | ret); |
315 | 901 | ||
316 | arizona_start_mic(info); | 902 | if (!arizona->pdata.hpdet_acc_id) { |
903 | info->detecting = true; | ||
904 | info->mic = false; | ||
905 | info->jack_flips = 0; | ||
906 | |||
907 | arizona_start_mic(info); | ||
908 | } else { | ||
909 | schedule_delayed_work(&info->hpdet_work, | ||
910 | msecs_to_jiffies(250)); | ||
911 | } | ||
912 | |||
913 | regmap_update_bits(arizona->regmap, | ||
914 | ARIZONA_JACK_DETECT_DEBOUNCE, | ||
915 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, 0); | ||
317 | } else { | 916 | } else { |
318 | dev_dbg(arizona->dev, "Detected jack removal\n"); | 917 | dev_dbg(arizona->dev, "Detected jack removal\n"); |
319 | 918 | ||
320 | arizona_stop_mic(info); | 919 | arizona_stop_mic(info); |
321 | 920 | ||
921 | info->num_hpdet_res = 0; | ||
922 | for (i = 0; i < ARRAY_SIZE(info->hpdet_res); i++) | ||
923 | info->hpdet_res[i] = 0; | ||
924 | info->mic = false; | ||
925 | info->hpdet_done = false; | ||
926 | |||
322 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) | 927 | for (i = 0; i < ARIZONA_NUM_BUTTONS; i++) |
323 | input_report_key(info->input, | 928 | input_report_key(info->input, |
324 | arizona_lvl_to_key[i].report, 0); | 929 | arizona_lvl_to_key[i].report, 0); |
@@ -328,8 +933,20 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
328 | if (ret != 0) | 933 | if (ret != 0) |
329 | dev_err(arizona->dev, "Removal report failed: %d\n", | 934 | dev_err(arizona->dev, "Removal report failed: %d\n", |
330 | ret); | 935 | ret); |
936 | |||
937 | regmap_update_bits(arizona->regmap, | ||
938 | ARIZONA_JACK_DETECT_DEBOUNCE, | ||
939 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB, | ||
940 | ARIZONA_MICD_CLAMP_DB | ARIZONA_JD1_DB); | ||
331 | } | 941 | } |
332 | 942 | ||
943 | /* Clear trig_sts to make sure DCVDD is not forced up */ | ||
944 | regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, | ||
945 | ARIZONA_MICD_CLAMP_FALL_TRIG_STS | | ||
946 | ARIZONA_MICD_CLAMP_RISE_TRIG_STS | | ||
947 | ARIZONA_JD1_FALL_TRIG_STS | | ||
948 | ARIZONA_JD1_RISE_TRIG_STS); | ||
949 | |||
333 | mutex_unlock(&info->lock); | 950 | mutex_unlock(&info->lock); |
334 | 951 | ||
335 | pm_runtime_mark_last_busy(info->dev); | 952 | pm_runtime_mark_last_busy(info->dev); |
@@ -343,8 +960,12 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
343 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | 960 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); |
344 | struct arizona_pdata *pdata; | 961 | struct arizona_pdata *pdata; |
345 | struct arizona_extcon_info *info; | 962 | struct arizona_extcon_info *info; |
963 | int jack_irq_fall, jack_irq_rise; | ||
346 | int ret, mode, i; | 964 | int ret, mode, i; |
347 | 965 | ||
966 | if (!arizona->dapm || !arizona->dapm->card) | ||
967 | return -EPROBE_DEFER; | ||
968 | |||
348 | pdata = dev_get_platdata(arizona->dev); | 969 | pdata = dev_get_platdata(arizona->dev); |
349 | 970 | ||
350 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | 971 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
@@ -364,7 +985,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
364 | mutex_init(&info->lock); | 985 | mutex_init(&info->lock); |
365 | info->arizona = arizona; | 986 | info->arizona = arizona; |
366 | info->dev = &pdev->dev; | 987 | info->dev = &pdev->dev; |
367 | info->detecting = true; | 988 | INIT_DELAYED_WORK(&info->hpdet_work, arizona_hpdet_work); |
368 | platform_set_drvdata(pdev, info); | 989 | platform_set_drvdata(pdev, info); |
369 | 990 | ||
370 | switch (arizona->type) { | 991 | switch (arizona->type) { |
@@ -374,6 +995,8 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
374 | info->micd_reva = true; | 995 | info->micd_reva = true; |
375 | break; | 996 | break; |
376 | default: | 997 | default: |
998 | info->micd_clamp = true; | ||
999 | info->hpdet_ip = 1; | ||
377 | break; | 1000 | break; |
378 | } | 1001 | } |
379 | break; | 1002 | break; |
@@ -416,9 +1039,64 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
416 | } | 1039 | } |
417 | } | 1040 | } |
418 | 1041 | ||
1042 | if (arizona->pdata.hpdet_id_gpio > 0) { | ||
1043 | ret = devm_gpio_request_one(&pdev->dev, | ||
1044 | arizona->pdata.hpdet_id_gpio, | ||
1045 | GPIOF_OUT_INIT_LOW, | ||
1046 | "HPDET"); | ||
1047 | if (ret != 0) { | ||
1048 | dev_err(arizona->dev, "Failed to request GPIO%d: %d\n", | ||
1049 | arizona->pdata.hpdet_id_gpio, ret); | ||
1050 | goto err_register; | ||
1051 | } | ||
1052 | } | ||
1053 | |||
1054 | if (arizona->pdata.micd_bias_start_time) | ||
1055 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, | ||
1056 | ARIZONA_MICD_BIAS_STARTTIME_MASK, | ||
1057 | arizona->pdata.micd_bias_start_time | ||
1058 | << ARIZONA_MICD_BIAS_STARTTIME_SHIFT); | ||
1059 | |||
1060 | if (arizona->pdata.micd_rate) | ||
1061 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, | ||
1062 | ARIZONA_MICD_RATE_MASK, | ||
1063 | arizona->pdata.micd_rate | ||
1064 | << ARIZONA_MICD_RATE_SHIFT); | ||
1065 | |||
1066 | if (arizona->pdata.micd_dbtime) | ||
1067 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, | ||
1068 | ARIZONA_MICD_DBTIME_MASK, | ||
1069 | arizona->pdata.micd_dbtime | ||
1070 | << ARIZONA_MICD_DBTIME_SHIFT); | ||
1071 | |||
1072 | /* | ||
1073 | * If we have a clamp use it, activating in conjunction with | ||
1074 | * GPIO5 if that is connected for jack detect operation. | ||
1075 | */ | ||
1076 | if (info->micd_clamp) { | ||
1077 | if (arizona->pdata.jd_gpio5) { | ||
1078 | /* Put the GPIO into input mode */ | ||
1079 | regmap_write(arizona->regmap, ARIZONA_GPIO5_CTRL, | ||
1080 | 0xc101); | ||
1081 | |||
1082 | regmap_update_bits(arizona->regmap, | ||
1083 | ARIZONA_MICD_CLAMP_CONTROL, | ||
1084 | ARIZONA_MICD_CLAMP_MODE_MASK, 0x9); | ||
1085 | } else { | ||
1086 | regmap_update_bits(arizona->regmap, | ||
1087 | ARIZONA_MICD_CLAMP_CONTROL, | ||
1088 | ARIZONA_MICD_CLAMP_MODE_MASK, 0x4); | ||
1089 | } | ||
1090 | |||
1091 | regmap_update_bits(arizona->regmap, | ||
1092 | ARIZONA_JACK_DETECT_DEBOUNCE, | ||
1093 | ARIZONA_MICD_CLAMP_DB, | ||
1094 | ARIZONA_MICD_CLAMP_DB); | ||
1095 | } | ||
1096 | |||
419 | arizona_extcon_set_mode(info, 0); | 1097 | arizona_extcon_set_mode(info, 0); |
420 | 1098 | ||
421 | info->input = input_allocate_device(); | 1099 | info->input = devm_input_allocate_device(&pdev->dev); |
422 | if (!info->input) { | 1100 | if (!info->input) { |
423 | dev_err(arizona->dev, "Can't allocate input dev\n"); | 1101 | dev_err(arizona->dev, "Can't allocate input dev\n"); |
424 | ret = -ENOMEM; | 1102 | ret = -ENOMEM; |
@@ -436,7 +1114,15 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
436 | pm_runtime_idle(&pdev->dev); | 1114 | pm_runtime_idle(&pdev->dev); |
437 | pm_runtime_get_sync(&pdev->dev); | 1115 | pm_runtime_get_sync(&pdev->dev); |
438 | 1116 | ||
439 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_JD_RISE, | 1117 | if (arizona->pdata.jd_gpio5) { |
1118 | jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; | ||
1119 | jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL; | ||
1120 | } else { | ||
1121 | jack_irq_rise = ARIZONA_IRQ_JD_RISE; | ||
1122 | jack_irq_fall = ARIZONA_IRQ_JD_FALL; | ||
1123 | } | ||
1124 | |||
1125 | ret = arizona_request_irq(arizona, jack_irq_rise, | ||
440 | "JACKDET rise", arizona_jackdet, info); | 1126 | "JACKDET rise", arizona_jackdet, info); |
441 | if (ret != 0) { | 1127 | if (ret != 0) { |
442 | dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n", | 1128 | dev_err(&pdev->dev, "Failed to get JACKDET rise IRQ: %d\n", |
@@ -444,21 +1130,21 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
444 | goto err_input; | 1130 | goto err_input; |
445 | } | 1131 | } |
446 | 1132 | ||
447 | ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 1); | 1133 | ret = arizona_set_irq_wake(arizona, jack_irq_rise, 1); |
448 | if (ret != 0) { | 1134 | if (ret != 0) { |
449 | dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n", | 1135 | dev_err(&pdev->dev, "Failed to set JD rise IRQ wake: %d\n", |
450 | ret); | 1136 | ret); |
451 | goto err_rise; | 1137 | goto err_rise; |
452 | } | 1138 | } |
453 | 1139 | ||
454 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_JD_FALL, | 1140 | ret = arizona_request_irq(arizona, jack_irq_fall, |
455 | "JACKDET fall", arizona_jackdet, info); | 1141 | "JACKDET fall", arizona_jackdet, info); |
456 | if (ret != 0) { | 1142 | if (ret != 0) { |
457 | dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret); | 1143 | dev_err(&pdev->dev, "Failed to get JD fall IRQ: %d\n", ret); |
458 | goto err_rise_wake; | 1144 | goto err_rise_wake; |
459 | } | 1145 | } |
460 | 1146 | ||
461 | ret = arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 1); | 1147 | ret = arizona_set_irq_wake(arizona, jack_irq_fall, 1); |
462 | if (ret != 0) { | 1148 | if (ret != 0) { |
463 | dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n", | 1149 | dev_err(&pdev->dev, "Failed to set JD fall IRQ wake: %d\n", |
464 | ret); | 1150 | ret); |
@@ -472,11 +1158,12 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
472 | goto err_fall_wake; | 1158 | goto err_fall_wake; |
473 | } | 1159 | } |
474 | 1160 | ||
475 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, | 1161 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_HPDET, |
476 | ARIZONA_MICD_BIAS_STARTTIME_MASK | | 1162 | "HPDET", arizona_hpdet_irq, info); |
477 | ARIZONA_MICD_RATE_MASK, | 1163 | if (ret != 0) { |
478 | 7 << ARIZONA_MICD_BIAS_STARTTIME_SHIFT | | 1164 | dev_err(&pdev->dev, "Failed to get HPDET IRQ: %d\n", ret); |
479 | 8 << ARIZONA_MICD_RATE_SHIFT); | 1165 | goto err_micdet; |
1166 | } | ||
480 | 1167 | ||
481 | arizona_clk32k_enable(arizona); | 1168 | arizona_clk32k_enable(arizona); |
482 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE, | 1169 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_DEBOUNCE, |
@@ -494,23 +1181,24 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
494 | ret = input_register_device(info->input); | 1181 | ret = input_register_device(info->input); |
495 | if (ret) { | 1182 | if (ret) { |
496 | dev_err(&pdev->dev, "Can't register input device: %d\n", ret); | 1183 | dev_err(&pdev->dev, "Can't register input device: %d\n", ret); |
497 | goto err_micdet; | 1184 | goto err_hpdet; |
498 | } | 1185 | } |
499 | 1186 | ||
500 | return 0; | 1187 | return 0; |
501 | 1188 | ||
1189 | err_hpdet: | ||
1190 | arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info); | ||
502 | err_micdet: | 1191 | err_micdet: |
503 | arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); | 1192 | arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); |
504 | err_fall_wake: | 1193 | err_fall_wake: |
505 | arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0); | 1194 | arizona_set_irq_wake(arizona, jack_irq_fall, 0); |
506 | err_fall: | 1195 | err_fall: |
507 | arizona_free_irq(arizona, ARIZONA_IRQ_JD_FALL, info); | 1196 | arizona_free_irq(arizona, jack_irq_fall, info); |
508 | err_rise_wake: | 1197 | err_rise_wake: |
509 | arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0); | 1198 | arizona_set_irq_wake(arizona, jack_irq_rise, 0); |
510 | err_rise: | 1199 | err_rise: |
511 | arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info); | 1200 | arizona_free_irq(arizona, jack_irq_rise, info); |
512 | err_input: | 1201 | err_input: |
513 | input_free_device(info->input); | ||
514 | err_register: | 1202 | err_register: |
515 | pm_runtime_disable(&pdev->dev); | 1203 | pm_runtime_disable(&pdev->dev); |
516 | extcon_dev_unregister(&info->edev); | 1204 | extcon_dev_unregister(&info->edev); |
@@ -522,18 +1210,32 @@ static int arizona_extcon_remove(struct platform_device *pdev) | |||
522 | { | 1210 | { |
523 | struct arizona_extcon_info *info = platform_get_drvdata(pdev); | 1211 | struct arizona_extcon_info *info = platform_get_drvdata(pdev); |
524 | struct arizona *arizona = info->arizona; | 1212 | struct arizona *arizona = info->arizona; |
1213 | int jack_irq_rise, jack_irq_fall; | ||
525 | 1214 | ||
526 | pm_runtime_disable(&pdev->dev); | 1215 | pm_runtime_disable(&pdev->dev); |
527 | 1216 | ||
528 | arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_RISE, 0); | 1217 | regmap_update_bits(arizona->regmap, |
529 | arizona_set_irq_wake(arizona, ARIZONA_IRQ_JD_FALL, 0); | 1218 | ARIZONA_MICD_CLAMP_CONTROL, |
1219 | ARIZONA_MICD_CLAMP_MODE_MASK, 0); | ||
1220 | |||
1221 | if (arizona->pdata.jd_gpio5) { | ||
1222 | jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; | ||
1223 | jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL; | ||
1224 | } else { | ||
1225 | jack_irq_rise = ARIZONA_IRQ_JD_RISE; | ||
1226 | jack_irq_fall = ARIZONA_IRQ_JD_FALL; | ||
1227 | } | ||
1228 | |||
1229 | arizona_set_irq_wake(arizona, jack_irq_rise, 0); | ||
1230 | arizona_set_irq_wake(arizona, jack_irq_fall, 0); | ||
1231 | arizona_free_irq(arizona, ARIZONA_IRQ_HPDET, info); | ||
530 | arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); | 1232 | arizona_free_irq(arizona, ARIZONA_IRQ_MICDET, info); |
531 | arizona_free_irq(arizona, ARIZONA_IRQ_JD_RISE, info); | 1233 | arizona_free_irq(arizona, jack_irq_rise, info); |
532 | arizona_free_irq(arizona, ARIZONA_IRQ_JD_FALL, info); | 1234 | arizona_free_irq(arizona, jack_irq_fall, info); |
1235 | cancel_delayed_work_sync(&info->hpdet_work); | ||
533 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, | 1236 | regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, |
534 | ARIZONA_JD1_ENA, 0); | 1237 | ARIZONA_JD1_ENA, 0); |
535 | arizona_clk32k_disable(arizona); | 1238 | arizona_clk32k_disable(arizona); |
536 | input_unregister_device(info->input); | ||
537 | extcon_dev_unregister(&info->edev); | 1239 | extcon_dev_unregister(&info->edev); |
538 | 1240 | ||
539 | return 0; | 1241 | return 0; |
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index 1b14bfcdc176..02bec32adde4 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <linux/workqueue.h> | 29 | #include <linux/workqueue.h> |
30 | #include <linux/gpio.h> | 30 | #include <linux/gpio.h> |
31 | #include <linux/extcon.h> | 31 | #include <linux/extcon.h> |
32 | #include <linux/extcon/extcon_gpio.h> | 32 | #include <linux/extcon/extcon-gpio.h> |
33 | 33 | ||
34 | struct gpio_extcon_data { | 34 | struct gpio_extcon_data { |
35 | struct extcon_dev edev; | 35 | struct extcon_dev edev; |
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 8c17b65eb74d..b70e3815c459 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/input.h> | ||
22 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
23 | #include <linux/err.h> | 24 | #include <linux/err.h> |
24 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
@@ -29,92 +30,7 @@ | |||
29 | #include <linux/irqdomain.h> | 30 | #include <linux/irqdomain.h> |
30 | 31 | ||
31 | #define DEV_NAME "max77693-muic" | 32 | #define DEV_NAME "max77693-muic" |
32 | 33 | #define DELAY_MS_DEFAULT 20000 /* unit: millisecond */ | |
33 | /* MAX77693 MUIC - STATUS1~3 Register */ | ||
34 | #define STATUS1_ADC_SHIFT (0) | ||
35 | #define STATUS1_ADCLOW_SHIFT (5) | ||
36 | #define STATUS1_ADCERR_SHIFT (6) | ||
37 | #define STATUS1_ADC1K_SHIFT (7) | ||
38 | #define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT) | ||
39 | #define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT) | ||
40 | #define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT) | ||
41 | #define STATUS1_ADC1K_MASK (0x1 << STATUS1_ADC1K_SHIFT) | ||
42 | |||
43 | #define STATUS2_CHGTYP_SHIFT (0) | ||
44 | #define STATUS2_CHGDETRUN_SHIFT (3) | ||
45 | #define STATUS2_DCDTMR_SHIFT (4) | ||
46 | #define STATUS2_DXOVP_SHIFT (5) | ||
47 | #define STATUS2_VBVOLT_SHIFT (6) | ||
48 | #define STATUS2_VIDRM_SHIFT (7) | ||
49 | #define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT) | ||
50 | #define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT) | ||
51 | #define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT) | ||
52 | #define STATUS2_DXOVP_MASK (0x1 << STATUS2_DXOVP_SHIFT) | ||
53 | #define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT) | ||
54 | #define STATUS2_VIDRM_MASK (0x1 << STATUS2_VIDRM_SHIFT) | ||
55 | |||
56 | #define STATUS3_OVP_SHIFT (2) | ||
57 | #define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT) | ||
58 | |||
59 | /* MAX77693 CDETCTRL1~2 register */ | ||
60 | #define CDETCTRL1_CHGDETEN_SHIFT (0) | ||
61 | #define CDETCTRL1_CHGTYPMAN_SHIFT (1) | ||
62 | #define CDETCTRL1_DCDEN_SHIFT (2) | ||
63 | #define CDETCTRL1_DCD2SCT_SHIFT (3) | ||
64 | #define CDETCTRL1_CDDELAY_SHIFT (4) | ||
65 | #define CDETCTRL1_DCDCPL_SHIFT (5) | ||
66 | #define CDETCTRL1_CDPDET_SHIFT (7) | ||
67 | #define CDETCTRL1_CHGDETEN_MASK (0x1 << CDETCTRL1_CHGDETEN_SHIFT) | ||
68 | #define CDETCTRL1_CHGTYPMAN_MASK (0x1 << CDETCTRL1_CHGTYPMAN_SHIFT) | ||
69 | #define CDETCTRL1_DCDEN_MASK (0x1 << CDETCTRL1_DCDEN_SHIFT) | ||
70 | #define CDETCTRL1_DCD2SCT_MASK (0x1 << CDETCTRL1_DCD2SCT_SHIFT) | ||
71 | #define CDETCTRL1_CDDELAY_MASK (0x1 << CDETCTRL1_CDDELAY_SHIFT) | ||
72 | #define CDETCTRL1_DCDCPL_MASK (0x1 << CDETCTRL1_DCDCPL_SHIFT) | ||
73 | #define CDETCTRL1_CDPDET_MASK (0x1 << CDETCTRL1_CDPDET_SHIFT) | ||
74 | |||
75 | #define CDETCTRL2_VIDRMEN_SHIFT (1) | ||
76 | #define CDETCTRL2_DXOVPEN_SHIFT (3) | ||
77 | #define CDETCTRL2_VIDRMEN_MASK (0x1 << CDETCTRL2_VIDRMEN_SHIFT) | ||
78 | #define CDETCTRL2_DXOVPEN_MASK (0x1 << CDETCTRL2_DXOVPEN_SHIFT) | ||
79 | |||
80 | /* MAX77693 MUIC - CONTROL1~3 register */ | ||
81 | #define COMN1SW_SHIFT (0) | ||
82 | #define COMP2SW_SHIFT (3) | ||
83 | #define COMN1SW_MASK (0x7 << COMN1SW_SHIFT) | ||
84 | #define COMP2SW_MASK (0x7 << COMP2SW_SHIFT) | ||
85 | #define COMP_SW_MASK (COMP2SW_MASK | COMN1SW_MASK) | ||
86 | #define CONTROL1_SW_USB ((1 << COMP2SW_SHIFT) \ | ||
87 | | (1 << COMN1SW_SHIFT)) | ||
88 | #define CONTROL1_SW_AUDIO ((2 << COMP2SW_SHIFT) \ | ||
89 | | (2 << COMN1SW_SHIFT)) | ||
90 | #define CONTROL1_SW_UART ((3 << COMP2SW_SHIFT) \ | ||
91 | | (3 << COMN1SW_SHIFT)) | ||
92 | #define CONTROL1_SW_OPEN ((0 << COMP2SW_SHIFT) \ | ||
93 | | (0 << COMN1SW_SHIFT)) | ||
94 | |||
95 | #define CONTROL2_LOWPWR_SHIFT (0) | ||
96 | #define CONTROL2_ADCEN_SHIFT (1) | ||
97 | #define CONTROL2_CPEN_SHIFT (2) | ||
98 | #define CONTROL2_SFOUTASRT_SHIFT (3) | ||
99 | #define CONTROL2_SFOUTORD_SHIFT (4) | ||
100 | #define CONTROL2_ACCDET_SHIFT (5) | ||
101 | #define CONTROL2_USBCPINT_SHIFT (6) | ||
102 | #define CONTROL2_RCPS_SHIFT (7) | ||
103 | #define CONTROL2_LOWPWR_MASK (0x1 << CONTROL2_LOWPWR_SHIFT) | ||
104 | #define CONTROL2_ADCEN_MASK (0x1 << CONTROL2_ADCEN_SHIFT) | ||
105 | #define CONTROL2_CPEN_MASK (0x1 << CONTROL2_CPEN_SHIFT) | ||
106 | #define CONTROL2_SFOUTASRT_MASK (0x1 << CONTROL2_SFOUTASRT_SHIFT) | ||
107 | #define CONTROL2_SFOUTORD_MASK (0x1 << CONTROL2_SFOUTORD_SHIFT) | ||
108 | #define CONTROL2_ACCDET_MASK (0x1 << CONTROL2_ACCDET_SHIFT) | ||
109 | #define CONTROL2_USBCPINT_MASK (0x1 << CONTROL2_USBCPINT_SHIFT) | ||
110 | #define CONTROL2_RCPS_MASK (0x1 << CONTROL2_RCPS_SHIFT) | ||
111 | |||
112 | #define CONTROL3_JIGSET_SHIFT (0) | ||
113 | #define CONTROL3_BTLDSET_SHIFT (2) | ||
114 | #define CONTROL3_ADCDBSET_SHIFT (4) | ||
115 | #define CONTROL3_JIGSET_MASK (0x3 << CONTROL3_JIGSET_SHIFT) | ||
116 | #define CONTROL3_BTLDSET_MASK (0x3 << CONTROL3_BTLDSET_SHIFT) | ||
117 | #define CONTROL3_ADCDBSET_MASK (0x3 << CONTROL3_ADCDBSET_SHIFT) | ||
118 | 34 | ||
119 | enum max77693_muic_adc_debounce_time { | 35 | enum max77693_muic_adc_debounce_time { |
120 | ADC_DEBOUNCE_TIME_5MS = 0, | 36 | ADC_DEBOUNCE_TIME_5MS = 0, |
@@ -127,14 +43,40 @@ struct max77693_muic_info { | |||
127 | struct device *dev; | 43 | struct device *dev; |
128 | struct max77693_dev *max77693; | 44 | struct max77693_dev *max77693; |
129 | struct extcon_dev *edev; | 45 | struct extcon_dev *edev; |
130 | int prev_adc; | 46 | int prev_cable_type; |
131 | int prev_adc_gnd; | 47 | int prev_cable_type_gnd; |
132 | int prev_chg_type; | 48 | int prev_chg_type; |
49 | int prev_button_type; | ||
133 | u8 status[2]; | 50 | u8 status[2]; |
134 | 51 | ||
135 | int irq; | 52 | int irq; |
136 | struct work_struct irq_work; | 53 | struct work_struct irq_work; |
137 | struct mutex mutex; | 54 | struct mutex mutex; |
55 | |||
56 | /* | ||
57 | * Use delayed workqueue to detect cable state and then | ||
58 | * notify cable state to notifiee/platform through uevent. | ||
59 | * After completing the booting of platform, the extcon provider | ||
60 | * driver should notify cable state to upper layer. | ||
61 | */ | ||
62 | struct delayed_work wq_detcable; | ||
63 | |||
64 | /* Button of dock device */ | ||
65 | struct input_dev *dock; | ||
66 | |||
67 | /* | ||
68 | * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB | ||
69 | * h/w path of COMP2/COMN1 on CONTROL1 register. | ||
70 | */ | ||
71 | int path_usb; | ||
72 | int path_uart; | ||
73 | }; | ||
74 | |||
75 | enum max77693_muic_cable_group { | ||
76 | MAX77693_CABLE_GROUP_ADC = 0, | ||
77 | MAX77693_CABLE_GROUP_ADC_GND, | ||
78 | MAX77693_CABLE_GROUP_CHG, | ||
79 | MAX77693_CABLE_GROUP_VBVOLT, | ||
138 | }; | 80 | }; |
139 | 81 | ||
140 | enum max77693_muic_charger_type { | 82 | enum max77693_muic_charger_type { |
@@ -215,27 +157,59 @@ enum max77693_muic_acc_type { | |||
215 | 157 | ||
216 | /* The below accessories have same ADC value so ADCLow and | 158 | /* The below accessories have same ADC value so ADCLow and |
217 | ADC1K bit is used to separate specific accessory */ | 159 | ADC1K bit is used to separate specific accessory */ |
218 | MAX77693_MUIC_GND_USB_OTG = 0x100, /* ADC:0x0, ADCLow:0, ADC1K:0 */ | 160 | MAX77693_MUIC_GND_USB_OTG = 0x100, /* ADC:0x0, VBVolot:0, ADCLow:0, ADC1K:0 */ |
219 | MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* ADC:0x0, ADCLow:1, ADC1K:0 */ | 161 | MAX77693_MUIC_GND_USB_OTG_VB = 0x104, /* ADC:0x0, VBVolot:1, ADCLow:0, ADC1K:0 */ |
220 | MAX77693_MUIC_GND_MHL_CABLE = 0x103, /* ADC:0x0, ADCLow:1, ADC1K:1 */ | 162 | MAX77693_MUIC_GND_AV_CABLE_LOAD = 0x102,/* ADC:0x0, VBVolot:0, ADCLow:1, ADC1K:0 */ |
163 | MAX77693_MUIC_GND_MHL = 0x103, /* ADC:0x0, VBVolot:0, ADCLow:1, ADC1K:1 */ | ||
164 | MAX77693_MUIC_GND_MHL_VB = 0x107, /* ADC:0x0, VBVolot:1, ADCLow:1, ADC1K:1 */ | ||
221 | }; | 165 | }; |
222 | 166 | ||
223 | /* MAX77693 MUIC device support below list of accessories(external connector) */ | 167 | /* MAX77693 MUIC device support below list of accessories(external connector) */ |
224 | const char *max77693_extcon_cable[] = { | 168 | enum { |
225 | [0] = "USB", | 169 | EXTCON_CABLE_USB = 0, |
226 | [1] = "USB-Host", | 170 | EXTCON_CABLE_USB_HOST, |
227 | [2] = "TA", | 171 | EXTCON_CABLE_TA, |
228 | [3] = "Fast-charger", | 172 | EXTCON_CABLE_FAST_CHARGER, |
229 | [4] = "Slow-charger", | 173 | EXTCON_CABLE_SLOW_CHARGER, |
230 | [5] = "Charge-downstream", | 174 | EXTCON_CABLE_CHARGE_DOWNSTREAM, |
231 | [6] = "MHL", | 175 | EXTCON_CABLE_MHL, |
232 | [7] = "Audio-video-load", | 176 | EXTCON_CABLE_MHL_TA, |
233 | [8] = "Audio-video-noload", | 177 | EXTCON_CABLE_JIG_USB_ON, |
234 | [9] = "JIG", | 178 | EXTCON_CABLE_JIG_USB_OFF, |
179 | EXTCON_CABLE_JIG_UART_OFF, | ||
180 | EXTCON_CABLE_JIG_UART_ON, | ||
181 | EXTCON_CABLE_DOCK_SMART, | ||
182 | EXTCON_CABLE_DOCK_DESK, | ||
183 | EXTCON_CABLE_DOCK_AUDIO, | ||
184 | |||
185 | _EXTCON_CABLE_NUM, | ||
186 | }; | ||
187 | |||
188 | static const char *max77693_extcon_cable[] = { | ||
189 | [EXTCON_CABLE_USB] = "USB", | ||
190 | [EXTCON_CABLE_USB_HOST] = "USB-Host", | ||
191 | [EXTCON_CABLE_TA] = "TA", | ||
192 | [EXTCON_CABLE_FAST_CHARGER] = "Fast-charger", | ||
193 | [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger", | ||
194 | [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream", | ||
195 | [EXTCON_CABLE_MHL] = "MHL", | ||
196 | [EXTCON_CABLE_MHL_TA] = "MHL_TA", | ||
197 | [EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON", | ||
198 | [EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF", | ||
199 | [EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF", | ||
200 | [EXTCON_CABLE_JIG_UART_ON] = "Dock-Car", | ||
201 | [EXTCON_CABLE_DOCK_SMART] = "Dock-Smart", | ||
202 | [EXTCON_CABLE_DOCK_DESK] = "Dock-Desk", | ||
203 | [EXTCON_CABLE_DOCK_AUDIO] = "Dock-Audio", | ||
235 | 204 | ||
236 | NULL, | 205 | NULL, |
237 | }; | 206 | }; |
238 | 207 | ||
208 | /* | ||
209 | * max77693_muic_set_debounce_time - Set the debounce time of ADC | ||
210 | * @info: the instance including private data of max77693 MUIC | ||
211 | * @time: the debounce time of ADC | ||
212 | */ | ||
239 | static int max77693_muic_set_debounce_time(struct max77693_muic_info *info, | 213 | static int max77693_muic_set_debounce_time(struct max77693_muic_info *info, |
240 | enum max77693_muic_adc_debounce_time time) | 214 | enum max77693_muic_adc_debounce_time time) |
241 | { | 215 | { |
@@ -250,18 +224,29 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info, | |||
250 | MAX77693_MUIC_REG_CTRL3, | 224 | MAX77693_MUIC_REG_CTRL3, |
251 | time << CONTROL3_ADCDBSET_SHIFT, | 225 | time << CONTROL3_ADCDBSET_SHIFT, |
252 | CONTROL3_ADCDBSET_MASK); | 226 | CONTROL3_ADCDBSET_MASK); |
253 | if (ret) | 227 | if (ret) { |
254 | dev_err(info->dev, "failed to set ADC debounce time\n"); | 228 | dev_err(info->dev, "failed to set ADC debounce time\n"); |
229 | return -EAGAIN; | ||
230 | } | ||
255 | break; | 231 | break; |
256 | default: | 232 | default: |
257 | dev_err(info->dev, "invalid ADC debounce time\n"); | 233 | dev_err(info->dev, "invalid ADC debounce time\n"); |
258 | ret = -EINVAL; | 234 | return -EINVAL; |
259 | break; | ||
260 | } | 235 | } |
261 | 236 | ||
262 | return ret; | 237 | return 0; |
263 | }; | 238 | }; |
264 | 239 | ||
240 | /* | ||
241 | * max77693_muic_set_path - Set hardware line according to attached cable | ||
242 | * @info: the instance including private data of max77693 MUIC | ||
243 | * @value: the path according to attached cable | ||
244 | * @attached: the state of cable (true:attached, false:detached) | ||
245 | * | ||
246 | * The max77693 MUIC device share outside H/W line among a varity of cables | ||
247 | * so, this function set internal path of H/W line according to the type of | ||
248 | * attached cable. | ||
249 | */ | ||
265 | static int max77693_muic_set_path(struct max77693_muic_info *info, | 250 | static int max77693_muic_set_path(struct max77693_muic_info *info, |
266 | u8 val, bool attached) | 251 | u8 val, bool attached) |
267 | { | 252 | { |
@@ -277,7 +262,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info, | |||
277 | MAX77693_MUIC_REG_CTRL1, ctrl1, COMP_SW_MASK); | 262 | MAX77693_MUIC_REG_CTRL1, ctrl1, COMP_SW_MASK); |
278 | if (ret < 0) { | 263 | if (ret < 0) { |
279 | dev_err(info->dev, "failed to update MUIC register\n"); | 264 | dev_err(info->dev, "failed to update MUIC register\n"); |
280 | goto out; | 265 | return -EAGAIN; |
281 | } | 266 | } |
282 | 267 | ||
283 | if (attached) | 268 | if (attached) |
@@ -290,141 +275,457 @@ static int max77693_muic_set_path(struct max77693_muic_info *info, | |||
290 | CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK); | 275 | CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK); |
291 | if (ret < 0) { | 276 | if (ret < 0) { |
292 | dev_err(info->dev, "failed to update MUIC register\n"); | 277 | dev_err(info->dev, "failed to update MUIC register\n"); |
293 | goto out; | 278 | return -EAGAIN; |
294 | } | 279 | } |
295 | 280 | ||
296 | dev_info(info->dev, | 281 | dev_info(info->dev, |
297 | "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n", | 282 | "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n", |
298 | ctrl1, ctrl2, attached ? "attached" : "detached"); | 283 | ctrl1, ctrl2, attached ? "attached" : "detached"); |
299 | out: | 284 | |
300 | return ret; | 285 | return 0; |
301 | } | 286 | } |
302 | 287 | ||
303 | static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info, | 288 | /* |
304 | bool attached) | 289 | * max77693_muic_get_cable_type - Return cable type and check cable state |
290 | * @info: the instance including private data of max77693 MUIC | ||
291 | * @group: the path according to attached cable | ||
292 | * @attached: store cable state and return | ||
293 | * | ||
294 | * This function check the cable state either attached or detached, | ||
295 | * and then divide precise type of cable according to cable group. | ||
296 | * - MAX77693_CABLE_GROUP_ADC | ||
297 | * - MAX77693_CABLE_GROUP_ADC_GND | ||
298 | * - MAX77693_CABLE_GROUP_CHG | ||
299 | * - MAX77693_CABLE_GROUP_VBVOLT | ||
300 | */ | ||
301 | static int max77693_muic_get_cable_type(struct max77693_muic_info *info, | ||
302 | enum max77693_muic_cable_group group, bool *attached) | ||
305 | { | 303 | { |
306 | int ret = 0; | 304 | int cable_type = 0; |
307 | int type; | 305 | int adc; |
308 | int adc, adc1k, adclow; | 306 | int adc1k; |
307 | int adclow; | ||
308 | int vbvolt; | ||
309 | int chg_type; | ||
310 | |||
311 | switch (group) { | ||
312 | case MAX77693_CABLE_GROUP_ADC: | ||
313 | /* | ||
314 | * Read ADC value to check cable type and decide cable state | ||
315 | * according to cable type | ||
316 | */ | ||
317 | adc = info->status[0] & STATUS1_ADC_MASK; | ||
318 | adc >>= STATUS1_ADC_SHIFT; | ||
319 | |||
320 | /* | ||
321 | * Check current cable state/cable type and store cable type | ||
322 | * (info->prev_cable_type) for handling cable when cable is | ||
323 | * detached. | ||
324 | */ | ||
325 | if (adc == MAX77693_MUIC_ADC_OPEN) { | ||
326 | *attached = false; | ||
327 | |||
328 | cable_type = info->prev_cable_type; | ||
329 | info->prev_cable_type = MAX77693_MUIC_ADC_OPEN; | ||
330 | } else { | ||
331 | *attached = true; | ||
332 | |||
333 | cable_type = info->prev_cable_type = adc; | ||
334 | } | ||
335 | break; | ||
336 | case MAX77693_CABLE_GROUP_ADC_GND: | ||
337 | /* | ||
338 | * Read ADC value to check cable type and decide cable state | ||
339 | * according to cable type | ||
340 | */ | ||
341 | adc = info->status[0] & STATUS1_ADC_MASK; | ||
342 | adc >>= STATUS1_ADC_SHIFT; | ||
343 | |||
344 | /* | ||
345 | * Check current cable state/cable type and store cable type | ||
346 | * (info->prev_cable_type/_gnd) for handling cable when cable | ||
347 | * is detached. | ||
348 | */ | ||
349 | if (adc == MAX77693_MUIC_ADC_OPEN) { | ||
350 | *attached = false; | ||
351 | |||
352 | cable_type = info->prev_cable_type_gnd; | ||
353 | info->prev_cable_type_gnd = MAX77693_MUIC_ADC_OPEN; | ||
354 | } else { | ||
355 | *attached = true; | ||
356 | |||
357 | adclow = info->status[0] & STATUS1_ADCLOW_MASK; | ||
358 | adclow >>= STATUS1_ADCLOW_SHIFT; | ||
359 | adc1k = info->status[0] & STATUS1_ADC1K_MASK; | ||
360 | adc1k >>= STATUS1_ADC1K_SHIFT; | ||
361 | |||
362 | vbvolt = info->status[1] & STATUS2_VBVOLT_MASK; | ||
363 | vbvolt >>= STATUS2_VBVOLT_SHIFT; | ||
364 | |||
365 | /** | ||
366 | * [0x1][VBVolt][ADCLow][ADC1K] | ||
367 | * [0x1 0 0 0 ] : USB_OTG | ||
368 | * [0x1 1 0 0 ] : USB_OTG_VB | ||
369 | * [0x1 0 1 0 ] : Audio Video Cable with load | ||
370 | * [0x1 0 1 1 ] : MHL without charging connector | ||
371 | * [0x1 1 1 1 ] : MHL with charging connector | ||
372 | */ | ||
373 | cable_type = ((0x1 << 8) | ||
374 | | (vbvolt << 2) | ||
375 | | (adclow << 1) | ||
376 | | adc1k); | ||
377 | |||
378 | info->prev_cable_type = adc; | ||
379 | info->prev_cable_type_gnd = cable_type; | ||
380 | } | ||
309 | 381 | ||
310 | if (attached) { | 382 | break; |
383 | case MAX77693_CABLE_GROUP_CHG: | ||
384 | /* | ||
385 | * Read charger type to check cable type and decide cable state | ||
386 | * according to type of charger cable. | ||
387 | */ | ||
388 | chg_type = info->status[1] & STATUS2_CHGTYP_MASK; | ||
389 | chg_type >>= STATUS2_CHGTYP_SHIFT; | ||
390 | |||
391 | if (chg_type == MAX77693_CHARGER_TYPE_NONE) { | ||
392 | *attached = false; | ||
393 | |||
394 | cable_type = info->prev_chg_type; | ||
395 | info->prev_chg_type = MAX77693_CHARGER_TYPE_NONE; | ||
396 | } else { | ||
397 | *attached = true; | ||
398 | |||
399 | /* | ||
400 | * Check current cable state/cable type and store cable | ||
401 | * type(info->prev_chg_type) for handling cable when | ||
402 | * charger cable is detached. | ||
403 | */ | ||
404 | cable_type = info->prev_chg_type = chg_type; | ||
405 | } | ||
406 | |||
407 | break; | ||
408 | case MAX77693_CABLE_GROUP_VBVOLT: | ||
409 | /* | ||
410 | * Read ADC value to check cable type and decide cable state | ||
411 | * according to cable type | ||
412 | */ | ||
311 | adc = info->status[0] & STATUS1_ADC_MASK; | 413 | adc = info->status[0] & STATUS1_ADC_MASK; |
312 | adclow = info->status[0] & STATUS1_ADCLOW_MASK; | 414 | adc >>= STATUS1_ADC_SHIFT; |
313 | adclow >>= STATUS1_ADCLOW_SHIFT; | 415 | chg_type = info->status[1] & STATUS2_CHGTYP_MASK; |
314 | adc1k = info->status[0] & STATUS1_ADC1K_MASK; | 416 | chg_type >>= STATUS2_CHGTYP_SHIFT; |
315 | adc1k >>= STATUS1_ADC1K_SHIFT; | 417 | |
316 | 418 | if (adc == MAX77693_MUIC_ADC_OPEN | |
317 | /** | 419 | && chg_type == MAX77693_CHARGER_TYPE_NONE) |
318 | * [0x1][ADCLow][ADC1K] | 420 | *attached = false; |
319 | * [0x1 0 0 ] : USB_OTG | 421 | else |
320 | * [0x1 1 0 ] : Audio Video Cable with load | 422 | *attached = true; |
321 | * [0x1 1 1 ] : MHL | 423 | |
424 | /* | ||
425 | * Read vbvolt field, if vbvolt is 1, | ||
426 | * this cable is used for charging. | ||
427 | */ | ||
428 | vbvolt = info->status[1] & STATUS2_VBVOLT_MASK; | ||
429 | vbvolt >>= STATUS2_VBVOLT_SHIFT; | ||
430 | |||
431 | cable_type = vbvolt; | ||
432 | break; | ||
433 | default: | ||
434 | dev_err(info->dev, "Unknown cable group (%d)\n", group); | ||
435 | cable_type = -EINVAL; | ||
436 | break; | ||
437 | } | ||
438 | |||
439 | return cable_type; | ||
440 | } | ||
441 | |||
442 | static int max77693_muic_dock_handler(struct max77693_muic_info *info, | ||
443 | int cable_type, bool attached) | ||
444 | { | ||
445 | int ret = 0; | ||
446 | int vbvolt; | ||
447 | bool cable_attached; | ||
448 | char dock_name[CABLE_NAME_MAX]; | ||
449 | |||
450 | dev_info(info->dev, | ||
451 | "external connector is %s (adc:0x%02x)\n", | ||
452 | attached ? "attached" : "detached", cable_type); | ||
453 | |||
454 | switch (cable_type) { | ||
455 | case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ | ||
456 | /* | ||
457 | * Check power cable whether attached or detached state. | ||
458 | * The Dock-Smart device need surely external power supply. | ||
459 | * If power cable(USB/TA) isn't connected to Dock device, | ||
460 | * user can't use Dock-Smart for desktop mode. | ||
461 | */ | ||
462 | vbvolt = max77693_muic_get_cable_type(info, | ||
463 | MAX77693_CABLE_GROUP_VBVOLT, &cable_attached); | ||
464 | if (attached && !vbvolt) { | ||
465 | dev_warn(info->dev, | ||
466 | "Cannot detect external power supply\n"); | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | /* | ||
471 | * Notify Dock-Smart/MHL state. | ||
472 | * - Dock-Smart device include three type of cable which | ||
473 | * are HDMI, USB for mouse/keyboard and micro-usb port | ||
474 | * for USB/TA cable. Dock-Smart device need always exteranl | ||
475 | * power supply(USB/TA cable through micro-usb cable). Dock- | ||
476 | * Smart device support screen output of target to separate | ||
477 | * monitor and mouse/keyboard for desktop mode. | ||
478 | * | ||
479 | * Features of 'USB/TA cable with Dock-Smart device' | ||
480 | * - Support MHL | ||
481 | * - Support external output feature of audio | ||
482 | * - Support charging through micro-usb port without data | ||
483 | * connection if TA cable is connected to target. | ||
484 | * - Support charging and data connection through micro-usb port | ||
485 | * if USB cable is connected between target and host | ||
486 | * device. | ||
487 | * - Support OTG device (Mouse/Keyboard) | ||
322 | */ | 488 | */ |
323 | type = ((0x1 << 8) | (adclow << 1) | adc1k); | 489 | ret = max77693_muic_set_path(info, info->path_usb, attached); |
490 | if (ret < 0) | ||
491 | return ret; | ||
492 | |||
493 | extcon_set_cable_state(info->edev, "Dock-Smart", attached); | ||
494 | extcon_set_cable_state(info->edev, "MHL", attached); | ||
495 | goto out; | ||
496 | case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* Dock-Car */ | ||
497 | strcpy(dock_name, "Dock-Car"); | ||
498 | break; | ||
499 | case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */ | ||
500 | strcpy(dock_name, "Dock-Desk"); | ||
501 | break; | ||
502 | case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */ | ||
503 | strcpy(dock_name, "Dock-Audio"); | ||
504 | if (!attached) | ||
505 | extcon_set_cable_state(info->edev, "USB", false); | ||
506 | break; | ||
507 | default: | ||
508 | dev_err(info->dev, "failed to detect %s dock device\n", | ||
509 | attached ? "attached" : "detached"); | ||
510 | return -EINVAL; | ||
511 | } | ||
512 | |||
513 | /* Dock-Car/Desk/Audio, PATH:AUDIO */ | ||
514 | ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); | ||
515 | if (ret < 0) | ||
516 | return ret; | ||
517 | extcon_set_cable_state(info->edev, dock_name, attached); | ||
518 | |||
519 | out: | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static int max77693_muic_dock_button_handler(struct max77693_muic_info *info, | ||
524 | int button_type, bool attached) | ||
525 | { | ||
526 | struct input_dev *dock = info->dock; | ||
527 | unsigned int code; | ||
528 | |||
529 | switch (button_type) { | ||
530 | case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON-1 | ||
531 | ... MAX77693_MUIC_ADC_REMOTE_S3_BUTTON+1: | ||
532 | /* DOCK_KEY_PREV */ | ||
533 | code = KEY_PREVIOUSSONG; | ||
534 | break; | ||
535 | case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON-1 | ||
536 | ... MAX77693_MUIC_ADC_REMOTE_S7_BUTTON+1: | ||
537 | /* DOCK_KEY_NEXT */ | ||
538 | code = KEY_NEXTSONG; | ||
539 | break; | ||
540 | case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON: | ||
541 | /* DOCK_VOL_DOWN */ | ||
542 | code = KEY_VOLUMEDOWN; | ||
543 | break; | ||
544 | case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON: | ||
545 | /* DOCK_VOL_UP */ | ||
546 | code = KEY_VOLUMEUP; | ||
547 | break; | ||
548 | case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON-1 | ||
549 | ... MAX77693_MUIC_ADC_REMOTE_S12_BUTTON+1: | ||
550 | /* DOCK_KEY_PLAY_PAUSE */ | ||
551 | code = KEY_PLAYPAUSE; | ||
552 | break; | ||
553 | default: | ||
554 | dev_err(info->dev, | ||
555 | "failed to detect %s key (adc:0x%x)\n", | ||
556 | attached ? "pressed" : "released", button_type); | ||
557 | return -EINVAL; | ||
558 | } | ||
559 | |||
560 | input_event(dock, EV_KEY, code, attached); | ||
561 | input_sync(dock); | ||
562 | |||
563 | return 0; | ||
564 | } | ||
324 | 565 | ||
325 | /* Store previous ADC value to handle accessory | 566 | static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) |
326 | when accessory will be detached */ | 567 | { |
327 | info->prev_adc = adc; | 568 | int cable_type_gnd; |
328 | info->prev_adc_gnd = type; | 569 | int ret = 0; |
329 | } else | 570 | bool attached; |
330 | type = info->prev_adc_gnd; | ||
331 | 571 | ||
332 | switch (type) { | 572 | cable_type_gnd = max77693_muic_get_cable_type(info, |
573 | MAX77693_CABLE_GROUP_ADC_GND, &attached); | ||
574 | |||
575 | switch (cable_type_gnd) { | ||
333 | case MAX77693_MUIC_GND_USB_OTG: | 576 | case MAX77693_MUIC_GND_USB_OTG: |
334 | /* USB_OTG */ | 577 | case MAX77693_MUIC_GND_USB_OTG_VB: |
578 | /* USB_OTG, PATH: AP_USB */ | ||
335 | ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); | 579 | ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); |
336 | if (ret < 0) | 580 | if (ret < 0) |
337 | goto out; | 581 | return ret; |
338 | extcon_set_cable_state(info->edev, "USB-Host", attached); | 582 | extcon_set_cable_state(info->edev, "USB-Host", attached); |
339 | break; | 583 | break; |
340 | case MAX77693_MUIC_GND_AV_CABLE_LOAD: | 584 | case MAX77693_MUIC_GND_AV_CABLE_LOAD: |
341 | /* Audio Video Cable with load */ | 585 | /* Audio Video Cable with load, PATH:AUDIO */ |
342 | ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); | 586 | ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); |
343 | if (ret < 0) | 587 | if (ret < 0) |
344 | goto out; | 588 | return ret; |
345 | extcon_set_cable_state(info->edev, | 589 | extcon_set_cable_state(info->edev, |
346 | "Audio-video-load", attached); | 590 | "Audio-video-load", attached); |
347 | break; | 591 | break; |
348 | case MAX77693_MUIC_GND_MHL_CABLE: | 592 | case MAX77693_MUIC_GND_MHL: |
349 | /* MHL */ | 593 | case MAX77693_MUIC_GND_MHL_VB: |
594 | /* MHL or MHL with USB/TA cable */ | ||
350 | extcon_set_cable_state(info->edev, "MHL", attached); | 595 | extcon_set_cable_state(info->edev, "MHL", attached); |
351 | break; | 596 | break; |
352 | default: | 597 | default: |
353 | dev_err(info->dev, "failed to detect %s accessory\n", | 598 | dev_err(info->dev, "failed to detect %s cable of gnd type\n", |
354 | attached ? "attached" : "detached"); | 599 | attached ? "attached" : "detached"); |
355 | dev_err(info->dev, "- adc:0x%x, adclow:0x%x, adc1k:0x%x\n", | 600 | return -EINVAL; |
356 | adc, adclow, adc1k); | 601 | } |
357 | ret = -EINVAL; | 602 | |
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static int max77693_muic_jig_handler(struct max77693_muic_info *info, | ||
607 | int cable_type, bool attached) | ||
608 | { | ||
609 | char cable_name[32]; | ||
610 | int ret = 0; | ||
611 | u8 path = CONTROL1_SW_OPEN; | ||
612 | |||
613 | dev_info(info->dev, | ||
614 | "external connector is %s (adc:0x%02x)\n", | ||
615 | attached ? "attached" : "detached", cable_type); | ||
616 | |||
617 | switch (cable_type) { | ||
618 | case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */ | ||
619 | /* PATH:AP_USB */ | ||
620 | strcpy(cable_name, "JIG-USB-OFF"); | ||
621 | path = CONTROL1_SW_USB; | ||
622 | break; | ||
623 | case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */ | ||
624 | /* PATH:AP_USB */ | ||
625 | strcpy(cable_name, "JIG-USB-ON"); | ||
626 | path = CONTROL1_SW_USB; | ||
358 | break; | 627 | break; |
628 | case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */ | ||
629 | /* PATH:AP_UART */ | ||
630 | strcpy(cable_name, "JIG-UART-OFF"); | ||
631 | path = CONTROL1_SW_UART; | ||
632 | break; | ||
633 | default: | ||
634 | dev_err(info->dev, "failed to detect %s jig cable\n", | ||
635 | attached ? "attached" : "detached"); | ||
636 | return -EINVAL; | ||
359 | } | 637 | } |
360 | 638 | ||
361 | out: | 639 | ret = max77693_muic_set_path(info, path, attached); |
362 | return ret; | 640 | if (ret < 0) |
641 | return ret; | ||
642 | |||
643 | extcon_set_cable_state(info->edev, cable_name, attached); | ||
644 | |||
645 | return 0; | ||
363 | } | 646 | } |
364 | 647 | ||
365 | static int max77693_muic_adc_handler(struct max77693_muic_info *info, | 648 | static int max77693_muic_adc_handler(struct max77693_muic_info *info) |
366 | int curr_adc, bool attached) | ||
367 | { | 649 | { |
650 | int cable_type; | ||
651 | int button_type; | ||
652 | bool attached; | ||
368 | int ret = 0; | 653 | int ret = 0; |
369 | int adc; | ||
370 | 654 | ||
371 | if (attached) { | 655 | /* Check accessory state which is either detached or attached */ |
372 | /* Store ADC value to handle accessory | 656 | cable_type = max77693_muic_get_cable_type(info, |
373 | when accessory will be detached */ | 657 | MAX77693_CABLE_GROUP_ADC, &attached); |
374 | info->prev_adc = curr_adc; | ||
375 | adc = curr_adc; | ||
376 | } else | ||
377 | adc = info->prev_adc; | ||
378 | 658 | ||
379 | dev_info(info->dev, | 659 | dev_info(info->dev, |
380 | "external connector is %s (adc:0x%02x, prev_adc:0x%x)\n", | 660 | "external connector is %s (adc:0x%02x, prev_adc:0x%x)\n", |
381 | attached ? "attached" : "detached", curr_adc, info->prev_adc); | 661 | attached ? "attached" : "detached", cable_type, |
662 | info->prev_cable_type); | ||
382 | 663 | ||
383 | switch (adc) { | 664 | switch (cable_type) { |
384 | case MAX77693_MUIC_ADC_GROUND: | 665 | case MAX77693_MUIC_ADC_GROUND: |
385 | /* USB_OTG/MHL/Audio */ | 666 | /* USB_OTG/MHL/Audio */ |
386 | max77693_muic_adc_ground_handler(info, attached); | 667 | max77693_muic_adc_ground_handler(info); |
387 | break; | 668 | break; |
388 | case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: | 669 | case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: |
389 | case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: | 670 | case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: |
390 | /* USB */ | ||
391 | ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); | ||
392 | if (ret < 0) | ||
393 | goto out; | ||
394 | extcon_set_cable_state(info->edev, "USB", attached); | ||
395 | break; | ||
396 | case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: | 671 | case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: |
397 | case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: | ||
398 | /* JIG */ | 672 | /* JIG */ |
399 | ret = max77693_muic_set_path(info, CONTROL1_SW_UART, attached); | 673 | ret = max77693_muic_jig_handler(info, cable_type, attached); |
400 | if (ret < 0) | 674 | if (ret < 0) |
401 | goto out; | 675 | return ret; |
402 | extcon_set_cable_state(info->edev, "JIG", attached); | ||
403 | break; | 676 | break; |
404 | case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: | 677 | case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ |
405 | /* Audio Video cable with no-load */ | 678 | case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* Dock-Car */ |
406 | ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); | 679 | case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */ |
680 | case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */ | ||
681 | /* | ||
682 | * DOCK device | ||
683 | * | ||
684 | * The MAX77693 MUIC device can detect total 34 cable type | ||
685 | * except of charger cable and MUIC device didn't define | ||
686 | * specfic role of cable in the range of from 0x01 to 0x12 | ||
687 | * of ADC value. So, can use/define cable with no role according | ||
688 | * to schema of hardware board. | ||
689 | */ | ||
690 | ret = max77693_muic_dock_handler(info, cable_type, attached); | ||
407 | if (ret < 0) | 691 | if (ret < 0) |
408 | goto out; | 692 | return ret; |
409 | extcon_set_cable_state(info->edev, | 693 | break; |
410 | "Audio-video-noload", attached); | 694 | case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON: /* DOCK_KEY_PREV */ |
695 | case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON: /* DOCK_KEY_NEXT */ | ||
696 | case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON: /* DOCK_VOL_DOWN */ | ||
697 | case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON: /* DOCK_VOL_UP */ | ||
698 | case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON: /* DOCK_KEY_PLAY_PAUSE */ | ||
699 | /* | ||
700 | * Button of DOCK device | ||
701 | * - the Prev/Next/Volume Up/Volume Down/Play-Pause button | ||
702 | * | ||
703 | * The MAX77693 MUIC device can detect total 34 cable type | ||
704 | * except of charger cable and MUIC device didn't define | ||
705 | * specfic role of cable in the range of from 0x01 to 0x12 | ||
706 | * of ADC value. So, can use/define cable with no role according | ||
707 | * to schema of hardware board. | ||
708 | */ | ||
709 | if (attached) | ||
710 | button_type = info->prev_button_type = cable_type; | ||
711 | else | ||
712 | button_type = info->prev_button_type; | ||
713 | |||
714 | ret = max77693_muic_dock_button_handler(info, button_type, | ||
715 | attached); | ||
716 | if (ret < 0) | ||
717 | return ret; | ||
411 | break; | 718 | break; |
412 | case MAX77693_MUIC_ADC_SEND_END_BUTTON: | 719 | case MAX77693_MUIC_ADC_SEND_END_BUTTON: |
413 | case MAX77693_MUIC_ADC_REMOTE_S1_BUTTON: | 720 | case MAX77693_MUIC_ADC_REMOTE_S1_BUTTON: |
414 | case MAX77693_MUIC_ADC_REMOTE_S2_BUTTON: | 721 | case MAX77693_MUIC_ADC_REMOTE_S2_BUTTON: |
415 | case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON: | ||
416 | case MAX77693_MUIC_ADC_REMOTE_S4_BUTTON: | 722 | case MAX77693_MUIC_ADC_REMOTE_S4_BUTTON: |
417 | case MAX77693_MUIC_ADC_REMOTE_S5_BUTTON: | 723 | case MAX77693_MUIC_ADC_REMOTE_S5_BUTTON: |
418 | case MAX77693_MUIC_ADC_REMOTE_S6_BUTTON: | 724 | case MAX77693_MUIC_ADC_REMOTE_S6_BUTTON: |
419 | case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON: | ||
420 | case MAX77693_MUIC_ADC_REMOTE_S8_BUTTON: | 725 | case MAX77693_MUIC_ADC_REMOTE_S8_BUTTON: |
421 | case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON: | ||
422 | case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON: | ||
423 | case MAX77693_MUIC_ADC_REMOTE_S11_BUTTON: | 726 | case MAX77693_MUIC_ADC_REMOTE_S11_BUTTON: |
424 | case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON: | ||
425 | case MAX77693_MUIC_ADC_RESERVED_ACC_1: | 727 | case MAX77693_MUIC_ADC_RESERVED_ACC_1: |
426 | case MAX77693_MUIC_ADC_RESERVED_ACC_2: | 728 | case MAX77693_MUIC_ADC_RESERVED_ACC_2: |
427 | case MAX77693_MUIC_ADC_RESERVED_ACC_3: | ||
428 | case MAX77693_MUIC_ADC_RESERVED_ACC_4: | 729 | case MAX77693_MUIC_ADC_RESERVED_ACC_4: |
429 | case MAX77693_MUIC_ADC_RESERVED_ACC_5: | 730 | case MAX77693_MUIC_ADC_RESERVED_ACC_5: |
430 | case MAX77693_MUIC_ADC_CEA936_AUDIO: | 731 | case MAX77693_MUIC_ADC_CEA936_AUDIO: |
@@ -432,60 +733,164 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info, | |||
432 | case MAX77693_MUIC_ADC_TTY_CONVERTER: | 733 | case MAX77693_MUIC_ADC_TTY_CONVERTER: |
433 | case MAX77693_MUIC_ADC_UART_CABLE: | 734 | case MAX77693_MUIC_ADC_UART_CABLE: |
434 | case MAX77693_MUIC_ADC_CEA936A_TYPE1_CHG: | 735 | case MAX77693_MUIC_ADC_CEA936A_TYPE1_CHG: |
435 | case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: | ||
436 | case MAX77693_MUIC_ADC_CEA936A_TYPE2_CHG: | 736 | case MAX77693_MUIC_ADC_CEA936A_TYPE2_CHG: |
437 | /* This accessory isn't used in general case if it is specially | 737 | /* |
438 | needed to detect additional accessory, should implement | 738 | * This accessory isn't used in general case if it is specially |
439 | proper operation when this accessory is attached/detached. */ | 739 | * needed to detect additional accessory, should implement |
740 | * proper operation when this accessory is attached/detached. | ||
741 | */ | ||
440 | dev_info(info->dev, | 742 | dev_info(info->dev, |
441 | "accessory is %s but it isn't used (adc:0x%x)\n", | 743 | "accessory is %s but it isn't used (adc:0x%x)\n", |
442 | attached ? "attached" : "detached", adc); | 744 | attached ? "attached" : "detached", cable_type); |
443 | goto out; | 745 | return -EAGAIN; |
444 | default: | 746 | default: |
445 | dev_err(info->dev, | 747 | dev_err(info->dev, |
446 | "failed to detect %s accessory (adc:0x%x)\n", | 748 | "failed to detect %s accessory (adc:0x%x)\n", |
447 | attached ? "attached" : "detached", adc); | 749 | attached ? "attached" : "detached", cable_type); |
448 | ret = -EINVAL; | 750 | return -EINVAL; |
449 | goto out; | ||
450 | } | 751 | } |
451 | 752 | ||
452 | out: | 753 | return 0; |
453 | return ret; | ||
454 | } | 754 | } |
455 | 755 | ||
456 | static int max77693_muic_chg_handler(struct max77693_muic_info *info, | 756 | static int max77693_muic_chg_handler(struct max77693_muic_info *info) |
457 | int curr_chg_type, bool attached) | ||
458 | { | 757 | { |
459 | int ret = 0; | ||
460 | int chg_type; | 758 | int chg_type; |
759 | int cable_type_gnd; | ||
760 | int cable_type; | ||
761 | bool attached; | ||
762 | bool cable_attached; | ||
763 | int ret = 0; | ||
461 | 764 | ||
462 | if (attached) { | 765 | chg_type = max77693_muic_get_cable_type(info, |
463 | /* Store previous charger type to control | 766 | MAX77693_CABLE_GROUP_CHG, &attached); |
464 | when charger accessory will be detached */ | ||
465 | info->prev_chg_type = curr_chg_type; | ||
466 | chg_type = curr_chg_type; | ||
467 | } else | ||
468 | chg_type = info->prev_chg_type; | ||
469 | 767 | ||
470 | dev_info(info->dev, | 768 | dev_info(info->dev, |
471 | "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n", | 769 | "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n", |
472 | attached ? "attached" : "detached", | 770 | attached ? "attached" : "detached", |
473 | curr_chg_type, info->prev_chg_type); | 771 | chg_type, info->prev_chg_type); |
474 | 772 | ||
475 | switch (chg_type) { | 773 | switch (chg_type) { |
476 | case MAX77693_CHARGER_TYPE_USB: | 774 | case MAX77693_CHARGER_TYPE_USB: |
477 | ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); | 775 | case MAX77693_CHARGER_TYPE_DEDICATED_CHG: |
478 | if (ret < 0) | 776 | case MAX77693_CHARGER_TYPE_NONE: |
479 | goto out; | 777 | /* Check MAX77693_CABLE_GROUP_ADC_GND type */ |
480 | extcon_set_cable_state(info->edev, "USB", attached); | 778 | cable_type_gnd = max77693_muic_get_cable_type(info, |
779 | MAX77693_CABLE_GROUP_ADC_GND, | ||
780 | &cable_attached); | ||
781 | switch (cable_type_gnd) { | ||
782 | case MAX77693_MUIC_GND_MHL: | ||
783 | case MAX77693_MUIC_GND_MHL_VB: | ||
784 | /* | ||
785 | * MHL cable with MHL_TA(USB/TA) cable | ||
786 | * - MHL cable include two port(HDMI line and separate micro- | ||
787 | * usb port. When the target connect MHL cable, extcon driver | ||
788 | * check whether MHL_TA(USB/TA) cable is connected. If MHL_TA | ||
789 | * cable is connected, extcon driver notify state to notifiee | ||
790 | * for charging battery. | ||
791 | * | ||
792 | * Features of 'MHL_TA(USB/TA) with MHL cable' | ||
793 | * - Support MHL | ||
794 | * - Support charging through micro-usb port without data connection | ||
795 | */ | ||
796 | extcon_set_cable_state(info->edev, "MHL_TA", attached); | ||
797 | if (!cable_attached) | ||
798 | extcon_set_cable_state(info->edev, "MHL", cable_attached); | ||
799 | break; | ||
800 | } | ||
801 | |||
802 | /* Check MAX77693_CABLE_GROUP_ADC type */ | ||
803 | cable_type = max77693_muic_get_cable_type(info, | ||
804 | MAX77693_CABLE_GROUP_ADC, | ||
805 | &cable_attached); | ||
806 | switch (cable_type) { | ||
807 | case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */ | ||
808 | /* | ||
809 | * Dock-Audio device with USB/TA cable | ||
810 | * - Dock device include two port(Dock-Audio and micro-usb | ||
811 | * port). When the target connect Dock-Audio device, extcon | ||
812 | * driver check whether USB/TA cable is connected. If USB/TA | ||
813 | * cable is connected, extcon driver notify state to notifiee | ||
814 | * for charging battery. | ||
815 | * | ||
816 | * Features of 'USB/TA cable with Dock-Audio device' | ||
817 | * - Support external output feature of audio. | ||
818 | * - Support charging through micro-usb port without data | ||
819 | * connection. | ||
820 | */ | ||
821 | extcon_set_cable_state(info->edev, "USB", attached); | ||
822 | |||
823 | if (!cable_attached) | ||
824 | extcon_set_cable_state(info->edev, "Dock-Audio", cable_attached); | ||
825 | break; | ||
826 | case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ | ||
827 | /* | ||
828 | * Dock-Smart device with USB/TA cable | ||
829 | * - Dock-Desk device include three type of cable which | ||
830 | * are HDMI, USB for mouse/keyboard and micro-usb port | ||
831 | * for USB/TA cable. Dock-Smart device need always exteranl | ||
832 | * power supply(USB/TA cable through micro-usb cable). Dock- | ||
833 | * Smart device support screen output of target to separate | ||
834 | * monitor and mouse/keyboard for desktop mode. | ||
835 | * | ||
836 | * Features of 'USB/TA cable with Dock-Smart device' | ||
837 | * - Support MHL | ||
838 | * - Support external output feature of audio | ||
839 | * - Support charging through micro-usb port without data | ||
840 | * connection if TA cable is connected to target. | ||
841 | * - Support charging and data connection through micro-usb port | ||
842 | * if USB cable is connected between target and host | ||
843 | * device. | ||
844 | * - Support OTG device (Mouse/Keyboard) | ||
845 | */ | ||
846 | ret = max77693_muic_set_path(info, info->path_usb, attached); | ||
847 | if (ret < 0) | ||
848 | return ret; | ||
849 | |||
850 | extcon_set_cable_state(info->edev, "Dock-Smart", attached); | ||
851 | extcon_set_cable_state(info->edev, "MHL", attached); | ||
852 | |||
853 | break; | ||
854 | } | ||
855 | |||
856 | /* Check MAX77693_CABLE_GROUP_CHG type */ | ||
857 | switch (chg_type) { | ||
858 | case MAX77693_CHARGER_TYPE_NONE: | ||
859 | /* | ||
860 | * When MHL(with USB/TA cable) or Dock-Audio with USB/TA cable | ||
861 | * is attached, muic device happen below two interrupt. | ||
862 | * - 'MAX77693_MUIC_IRQ_INT1_ADC' for detecting MHL/Dock-Audio. | ||
863 | * - 'MAX77693_MUIC_IRQ_INT2_CHGTYP' for detecting USB/TA cable | ||
864 | * connected to MHL or Dock-Audio. | ||
865 | * Always, happen eariler MAX77693_MUIC_IRQ_INT1_ADC interrupt | ||
866 | * than MAX77693_MUIC_IRQ_INT2_CHGTYP interrupt. | ||
867 | * | ||
868 | * If user attach MHL (with USB/TA cable and immediately detach | ||
869 | * MHL with USB/TA cable before MAX77693_MUIC_IRQ_INT2_CHGTYP | ||
870 | * interrupt is happened, USB/TA cable remain connected state to | ||
871 | * target. But USB/TA cable isn't connected to target. The user | ||
872 | * be face with unusual action. So, driver should check this | ||
873 | * situation in spite of, that previous charger type is N/A. | ||
874 | */ | ||
875 | break; | ||
876 | case MAX77693_CHARGER_TYPE_USB: | ||
877 | /* Only USB cable, PATH:AP_USB */ | ||
878 | ret = max77693_muic_set_path(info, info->path_usb, attached); | ||
879 | if (ret < 0) | ||
880 | return ret; | ||
881 | |||
882 | extcon_set_cable_state(info->edev, "USB", attached); | ||
883 | break; | ||
884 | case MAX77693_CHARGER_TYPE_DEDICATED_CHG: | ||
885 | /* Only TA cable */ | ||
886 | extcon_set_cable_state(info->edev, "TA", attached); | ||
887 | break; | ||
888 | } | ||
481 | break; | 889 | break; |
482 | case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT: | 890 | case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT: |
483 | extcon_set_cable_state(info->edev, | 891 | extcon_set_cable_state(info->edev, |
484 | "Charge-downstream", attached); | 892 | "Charge-downstream", attached); |
485 | break; | 893 | break; |
486 | case MAX77693_CHARGER_TYPE_DEDICATED_CHG: | ||
487 | extcon_set_cable_state(info->edev, "TA", attached); | ||
488 | break; | ||
489 | case MAX77693_CHARGER_TYPE_APPLE_500MA: | 894 | case MAX77693_CHARGER_TYPE_APPLE_500MA: |
490 | extcon_set_cable_state(info->edev, "Slow-charger", attached); | 895 | extcon_set_cable_state(info->edev, "Slow-charger", attached); |
491 | break; | 896 | break; |
@@ -498,22 +903,18 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info, | |||
498 | dev_err(info->dev, | 903 | dev_err(info->dev, |
499 | "failed to detect %s accessory (chg_type:0x%x)\n", | 904 | "failed to detect %s accessory (chg_type:0x%x)\n", |
500 | attached ? "attached" : "detached", chg_type); | 905 | attached ? "attached" : "detached", chg_type); |
501 | ret = -EINVAL; | 906 | return -EINVAL; |
502 | goto out; | ||
503 | } | 907 | } |
504 | 908 | ||
505 | out: | 909 | return 0; |
506 | return ret; | ||
507 | } | 910 | } |
508 | 911 | ||
509 | static void max77693_muic_irq_work(struct work_struct *work) | 912 | static void max77693_muic_irq_work(struct work_struct *work) |
510 | { | 913 | { |
511 | struct max77693_muic_info *info = container_of(work, | 914 | struct max77693_muic_info *info = container_of(work, |
512 | struct max77693_muic_info, irq_work); | 915 | struct max77693_muic_info, irq_work); |
513 | int curr_adc, curr_chg_type; | ||
514 | int irq_type = -1; | 916 | int irq_type = -1; |
515 | int i, ret = 0; | 917 | int i, ret = 0; |
516 | bool attached = true; | ||
517 | 918 | ||
518 | if (!info->edev) | 919 | if (!info->edev) |
519 | return; | 920 | return; |
@@ -539,14 +940,7 @@ static void max77693_muic_irq_work(struct work_struct *work) | |||
539 | case MAX77693_MUIC_IRQ_INT1_ADC1K: | 940 | case MAX77693_MUIC_IRQ_INT1_ADC1K: |
540 | /* Handle all of accessory except for | 941 | /* Handle all of accessory except for |
541 | type of charger accessory */ | 942 | type of charger accessory */ |
542 | curr_adc = info->status[0] & STATUS1_ADC_MASK; | 943 | ret = max77693_muic_adc_handler(info); |
543 | curr_adc >>= STATUS1_ADC_SHIFT; | ||
544 | |||
545 | /* Check accessory state which is either detached or attached */ | ||
546 | if (curr_adc == MAX77693_MUIC_ADC_OPEN) | ||
547 | attached = false; | ||
548 | |||
549 | ret = max77693_muic_adc_handler(info, curr_adc, attached); | ||
550 | break; | 944 | break; |
551 | case MAX77693_MUIC_IRQ_INT2_CHGTYP: | 945 | case MAX77693_MUIC_IRQ_INT2_CHGTYP: |
552 | case MAX77693_MUIC_IRQ_INT2_CHGDETREUN: | 946 | case MAX77693_MUIC_IRQ_INT2_CHGDETREUN: |
@@ -555,15 +949,7 @@ static void max77693_muic_irq_work(struct work_struct *work) | |||
555 | case MAX77693_MUIC_IRQ_INT2_VBVOLT: | 949 | case MAX77693_MUIC_IRQ_INT2_VBVOLT: |
556 | case MAX77693_MUIC_IRQ_INT2_VIDRM: | 950 | case MAX77693_MUIC_IRQ_INT2_VIDRM: |
557 | /* Handle charger accessory */ | 951 | /* Handle charger accessory */ |
558 | curr_chg_type = info->status[1] & STATUS2_CHGTYP_MASK; | 952 | ret = max77693_muic_chg_handler(info); |
559 | curr_chg_type >>= STATUS2_CHGTYP_SHIFT; | ||
560 | |||
561 | /* Check charger accessory state which | ||
562 | is either detached or attached */ | ||
563 | if (curr_chg_type == MAX77693_CHARGER_TYPE_NONE) | ||
564 | attached = false; | ||
565 | |||
566 | ret = max77693_muic_chg_handler(info, curr_chg_type, attached); | ||
567 | break; | 953 | break; |
568 | case MAX77693_MUIC_IRQ_INT3_EOC: | 954 | case MAX77693_MUIC_IRQ_INT3_EOC: |
569 | case MAX77693_MUIC_IRQ_INT3_CGMBC: | 955 | case MAX77693_MUIC_IRQ_INT3_CGMBC: |
@@ -575,7 +961,8 @@ static void max77693_muic_irq_work(struct work_struct *work) | |||
575 | default: | 961 | default: |
576 | dev_err(info->dev, "muic interrupt: irq %d occurred\n", | 962 | dev_err(info->dev, "muic interrupt: irq %d occurred\n", |
577 | irq_type); | 963 | irq_type); |
578 | break; | 964 | mutex_unlock(&info->mutex); |
965 | return; | ||
579 | } | 966 | } |
580 | 967 | ||
581 | if (ret < 0) | 968 | if (ret < 0) |
@@ -604,7 +991,9 @@ static struct regmap_config max77693_muic_regmap_config = { | |||
604 | static int max77693_muic_detect_accessory(struct max77693_muic_info *info) | 991 | static int max77693_muic_detect_accessory(struct max77693_muic_info *info) |
605 | { | 992 | { |
606 | int ret = 0; | 993 | int ret = 0; |
607 | int adc, chg_type; | 994 | int adc; |
995 | int chg_type; | ||
996 | bool attached; | ||
608 | 997 | ||
609 | mutex_lock(&info->mutex); | 998 | mutex_lock(&info->mutex); |
610 | 999 | ||
@@ -617,35 +1006,39 @@ static int max77693_muic_detect_accessory(struct max77693_muic_info *info) | |||
617 | return -EINVAL; | 1006 | return -EINVAL; |
618 | } | 1007 | } |
619 | 1008 | ||
620 | adc = info->status[0] & STATUS1_ADC_MASK; | 1009 | adc = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC, |
621 | adc >>= STATUS1_ADC_SHIFT; | 1010 | &attached); |
622 | 1011 | if (attached && adc != MAX77693_MUIC_ADC_OPEN) { | |
623 | if (adc != MAX77693_MUIC_ADC_OPEN) { | 1012 | ret = max77693_muic_adc_handler(info); |
624 | dev_info(info->dev, | 1013 | if (ret < 0) { |
625 | "external connector is attached (adc:0x%02x)\n", adc); | 1014 | dev_err(info->dev, "Cannot detect accessory\n"); |
1015 | mutex_unlock(&info->mutex); | ||
1016 | return ret; | ||
1017 | } | ||
1018 | } | ||
626 | 1019 | ||
627 | ret = max77693_muic_adc_handler(info, adc, true); | 1020 | chg_type = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_CHG, |
628 | if (ret < 0) | 1021 | &attached); |
629 | dev_err(info->dev, "failed to detect accessory\n"); | 1022 | if (attached && chg_type != MAX77693_CHARGER_TYPE_NONE) { |
630 | goto out; | 1023 | ret = max77693_muic_chg_handler(info); |
1024 | if (ret < 0) { | ||
1025 | dev_err(info->dev, "Cannot detect charger accessory\n"); | ||
1026 | mutex_unlock(&info->mutex); | ||
1027 | return ret; | ||
1028 | } | ||
631 | } | 1029 | } |
632 | 1030 | ||
633 | chg_type = info->status[1] & STATUS2_CHGTYP_MASK; | 1031 | mutex_unlock(&info->mutex); |
634 | chg_type >>= STATUS2_CHGTYP_SHIFT; | ||
635 | 1032 | ||
636 | if (chg_type != MAX77693_CHARGER_TYPE_NONE) { | 1033 | return 0; |
637 | dev_info(info->dev, | 1034 | } |
638 | "external connector is attached (chg_type:0x%x)\n", | ||
639 | chg_type); | ||
640 | 1035 | ||
641 | max77693_muic_chg_handler(info, chg_type, true); | 1036 | static void max77693_muic_detect_cable_wq(struct work_struct *work) |
642 | if (ret < 0) | 1037 | { |
643 | dev_err(info->dev, "failed to detect charger accessory\n"); | 1038 | struct max77693_muic_info *info = container_of(to_delayed_work(work), |
644 | } | 1039 | struct max77693_muic_info, wq_detcable); |
645 | 1040 | ||
646 | out: | 1041 | max77693_muic_detect_accessory(info); |
647 | mutex_unlock(&info->mutex); | ||
648 | return ret; | ||
649 | } | 1042 | } |
650 | 1043 | ||
651 | static int max77693_muic_probe(struct platform_device *pdev) | 1044 | static int max77693_muic_probe(struct platform_device *pdev) |
@@ -654,7 +1047,9 @@ static int max77693_muic_probe(struct platform_device *pdev) | |||
654 | struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); | 1047 | struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); |
655 | struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; | 1048 | struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; |
656 | struct max77693_muic_info *info; | 1049 | struct max77693_muic_info *info; |
657 | int ret, i; | 1050 | int delay_jiffies; |
1051 | int ret; | ||
1052 | int i; | ||
658 | u8 id; | 1053 | u8 id; |
659 | 1054 | ||
660 | info = devm_kzalloc(&pdev->dev, sizeof(struct max77693_muic_info), | 1055 | info = devm_kzalloc(&pdev->dev, sizeof(struct max77693_muic_info), |
@@ -678,6 +1073,32 @@ static int max77693_muic_probe(struct platform_device *pdev) | |||
678 | return ret; | 1073 | return ret; |
679 | } | 1074 | } |
680 | } | 1075 | } |
1076 | |||
1077 | /* Register input device for button of dock device */ | ||
1078 | info->dock = devm_input_allocate_device(&pdev->dev); | ||
1079 | if (!info->dock) { | ||
1080 | dev_err(&pdev->dev, "%s: failed to allocate input\n", __func__); | ||
1081 | return -ENOMEM; | ||
1082 | } | ||
1083 | info->dock->name = "max77693-muic/dock"; | ||
1084 | info->dock->phys = "max77693-muic/extcon"; | ||
1085 | info->dock->dev.parent = &pdev->dev; | ||
1086 | |||
1087 | __set_bit(EV_REP, info->dock->evbit); | ||
1088 | |||
1089 | input_set_capability(info->dock, EV_KEY, KEY_VOLUMEUP); | ||
1090 | input_set_capability(info->dock, EV_KEY, KEY_VOLUMEDOWN); | ||
1091 | input_set_capability(info->dock, EV_KEY, KEY_PLAYPAUSE); | ||
1092 | input_set_capability(info->dock, EV_KEY, KEY_PREVIOUSSONG); | ||
1093 | input_set_capability(info->dock, EV_KEY, KEY_NEXTSONG); | ||
1094 | |||
1095 | ret = input_register_device(info->dock); | ||
1096 | if (ret < 0) { | ||
1097 | dev_err(&pdev->dev, "Cannot register input device error(%d)\n", | ||
1098 | ret); | ||
1099 | return ret; | ||
1100 | } | ||
1101 | |||
681 | platform_set_drvdata(pdev, info); | 1102 | platform_set_drvdata(pdev, info); |
682 | mutex_init(&info->mutex); | 1103 | mutex_init(&info->mutex); |
683 | 1104 | ||
@@ -697,13 +1118,13 @@ static int max77693_muic_probe(struct platform_device *pdev) | |||
697 | 1118 | ||
698 | ret = request_threaded_irq(virq, NULL, | 1119 | ret = request_threaded_irq(virq, NULL, |
699 | max77693_muic_irq_handler, | 1120 | max77693_muic_irq_handler, |
700 | IRQF_ONESHOT, muic_irq->name, info); | 1121 | IRQF_NO_SUSPEND, |
1122 | muic_irq->name, info); | ||
701 | if (ret) { | 1123 | if (ret) { |
702 | dev_err(&pdev->dev, | 1124 | dev_err(&pdev->dev, |
703 | "failed: irq request (IRQ: %d," | 1125 | "failed: irq request (IRQ: %d," |
704 | " error :%d)\n", | 1126 | " error :%d)\n", |
705 | muic_irq->irq, ret); | 1127 | muic_irq->irq, ret); |
706 | |||
707 | goto err_irq; | 1128 | goto err_irq; |
708 | } | 1129 | } |
709 | } | 1130 | } |
@@ -749,23 +1170,54 @@ static int max77693_muic_probe(struct platform_device *pdev) | |||
749 | = muic_pdata->init_data[i].data; | 1170 | = muic_pdata->init_data[i].data; |
750 | } | 1171 | } |
751 | 1172 | ||
1173 | /* | ||
1174 | * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB | ||
1175 | * h/w path of COMP2/COMN1 on CONTROL1 register. | ||
1176 | */ | ||
1177 | if (muic_pdata->path_uart) | ||
1178 | info->path_uart = muic_pdata->path_uart; | ||
1179 | else | ||
1180 | info->path_uart = CONTROL1_SW_UART; | ||
1181 | |||
1182 | if (muic_pdata->path_usb) | ||
1183 | info->path_usb = muic_pdata->path_usb; | ||
1184 | else | ||
1185 | info->path_usb = CONTROL1_SW_USB; | ||
1186 | |||
1187 | /* Set initial path for UART */ | ||
1188 | max77693_muic_set_path(info, info->path_uart, true); | ||
1189 | |||
752 | /* Check revision number of MUIC device*/ | 1190 | /* Check revision number of MUIC device*/ |
753 | ret = max77693_read_reg(info->max77693->regmap_muic, | 1191 | ret = max77693_read_reg(info->max77693->regmap_muic, |
754 | MAX77693_MUIC_REG_ID, &id); | 1192 | MAX77693_MUIC_REG_ID, &id); |
755 | if (ret < 0) { | 1193 | if (ret < 0) { |
756 | dev_err(&pdev->dev, "failed to read revision number\n"); | 1194 | dev_err(&pdev->dev, "failed to read revision number\n"); |
757 | goto err_irq; | 1195 | goto err_extcon; |
758 | } | 1196 | } |
759 | dev_info(info->dev, "device ID : 0x%x\n", id); | 1197 | dev_info(info->dev, "device ID : 0x%x\n", id); |
760 | 1198 | ||
761 | /* Set ADC debounce time */ | 1199 | /* Set ADC debounce time */ |
762 | max77693_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS); | 1200 | max77693_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS); |
763 | 1201 | ||
764 | /* Detect accessory on boot */ | 1202 | /* |
765 | max77693_muic_detect_accessory(info); | 1203 | * Detect accessory after completing the initialization of platform |
1204 | * | ||
1205 | * - Use delayed workqueue to detect cable state and then | ||
1206 | * notify cable state to notifiee/platform through uevent. | ||
1207 | * After completing the booting of platform, the extcon provider | ||
1208 | * driver should notify cable state to upper layer. | ||
1209 | */ | ||
1210 | INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq); | ||
1211 | if (muic_pdata->detcable_delay_ms) | ||
1212 | delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms); | ||
1213 | else | ||
1214 | delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); | ||
1215 | schedule_delayed_work(&info->wq_detcable, delay_jiffies); | ||
766 | 1216 | ||
767 | return ret; | 1217 | return ret; |
768 | 1218 | ||
1219 | err_extcon: | ||
1220 | extcon_dev_unregister(info->edev); | ||
769 | err_irq: | 1221 | err_irq: |
770 | while (--i >= 0) | 1222 | while (--i >= 0) |
771 | free_irq(muic_irqs[i].virq, info); | 1223 | free_irq(muic_irqs[i].virq, info); |
@@ -780,6 +1232,7 @@ static int max77693_muic_remove(struct platform_device *pdev) | |||
780 | for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) | 1232 | for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) |
781 | free_irq(muic_irqs[i].virq, info); | 1233 | free_irq(muic_irqs[i].virq, info); |
782 | cancel_work_sync(&info->irq_work); | 1234 | cancel_work_sync(&info->irq_work); |
1235 | input_unregister_device(info->dock); | ||
783 | extcon_dev_unregister(info->edev); | 1236 | extcon_dev_unregister(info->edev); |
784 | 1237 | ||
785 | return 0; | 1238 | return 0; |
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 93009fe6ef05..e636d950ad6c 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c | |||
@@ -29,51 +29,14 @@ | |||
29 | #include <linux/irqdomain.h> | 29 | #include <linux/irqdomain.h> |
30 | 30 | ||
31 | #define DEV_NAME "max8997-muic" | 31 | #define DEV_NAME "max8997-muic" |
32 | #define DELAY_MS_DEFAULT 20000 /* unit: millisecond */ | ||
32 | 33 | ||
33 | /* MAX8997-MUIC STATUS1 register */ | 34 | enum max8997_muic_adc_debounce_time { |
34 | #define STATUS1_ADC_SHIFT 0 | 35 | ADC_DEBOUNCE_TIME_0_5MS = 0, /* 0.5ms */ |
35 | #define STATUS1_ADCLOW_SHIFT 5 | 36 | ADC_DEBOUNCE_TIME_10MS, /* 10ms */ |
36 | #define STATUS1_ADCERR_SHIFT 6 | 37 | ADC_DEBOUNCE_TIME_25MS, /* 25ms */ |
37 | #define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT) | 38 | ADC_DEBOUNCE_TIME_38_62MS, /* 38.62ms */ |
38 | #define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT) | 39 | }; |
39 | #define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT) | ||
40 | |||
41 | /* MAX8997-MUIC STATUS2 register */ | ||
42 | #define STATUS2_CHGTYP_SHIFT 0 | ||
43 | #define STATUS2_CHGDETRUN_SHIFT 3 | ||
44 | #define STATUS2_DCDTMR_SHIFT 4 | ||
45 | #define STATUS2_DBCHG_SHIFT 5 | ||
46 | #define STATUS2_VBVOLT_SHIFT 6 | ||
47 | #define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT) | ||
48 | #define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT) | ||
49 | #define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT) | ||
50 | #define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT) | ||
51 | #define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT) | ||
52 | |||
53 | /* MAX8997-MUIC STATUS3 register */ | ||
54 | #define STATUS3_OVP_SHIFT 2 | ||
55 | #define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT) | ||
56 | |||
57 | /* MAX8997-MUIC CONTROL1 register */ | ||
58 | #define COMN1SW_SHIFT 0 | ||
59 | #define COMP2SW_SHIFT 3 | ||
60 | #define COMN1SW_MASK (0x7 << COMN1SW_SHIFT) | ||
61 | #define COMP2SW_MASK (0x7 << COMP2SW_SHIFT) | ||
62 | #define SW_MASK (COMP2SW_MASK | COMN1SW_MASK) | ||
63 | |||
64 | #define MAX8997_SW_USB ((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT)) | ||
65 | #define MAX8997_SW_AUDIO ((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT)) | ||
66 | #define MAX8997_SW_UART ((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT)) | ||
67 | #define MAX8997_SW_OPEN ((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT)) | ||
68 | |||
69 | #define MAX8997_ADC_GROUND 0x00 | ||
70 | #define MAX8997_ADC_MHL 0x01 | ||
71 | #define MAX8997_ADC_JIG_USB_1 0x18 | ||
72 | #define MAX8997_ADC_JIG_USB_2 0x19 | ||
73 | #define MAX8997_ADC_DESKDOCK 0x1a | ||
74 | #define MAX8997_ADC_JIG_UART 0x1c | ||
75 | #define MAX8997_ADC_CARDOCK 0x1d | ||
76 | #define MAX8997_ADC_OPEN 0x1f | ||
77 | 40 | ||
78 | struct max8997_muic_irq { | 41 | struct max8997_muic_irq { |
79 | unsigned int irq; | 42 | unsigned int irq; |
@@ -82,61 +45,303 @@ struct max8997_muic_irq { | |||
82 | }; | 45 | }; |
83 | 46 | ||
84 | static struct max8997_muic_irq muic_irqs[] = { | 47 | static struct max8997_muic_irq muic_irqs[] = { |
85 | { MAX8997_MUICIRQ_ADCError, "muic-ADC_error" }, | 48 | { MAX8997_MUICIRQ_ADCError, "muic-ADCERROR" }, |
86 | { MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" }, | 49 | { MAX8997_MUICIRQ_ADCLow, "muic-ADCLOW" }, |
87 | { MAX8997_MUICIRQ_ADC, "muic-ADC" }, | 50 | { MAX8997_MUICIRQ_ADC, "muic-ADC" }, |
88 | { MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" }, | 51 | { MAX8997_MUICIRQ_VBVolt, "muic-VBVOLT" }, |
89 | { MAX8997_MUICIRQ_DBChg, "muic-DB_charger" }, | 52 | { MAX8997_MUICIRQ_DBChg, "muic-DBCHG" }, |
90 | { MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" }, | 53 | { MAX8997_MUICIRQ_DCDTmr, "muic-DCDTMR" }, |
91 | { MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" }, | 54 | { MAX8997_MUICIRQ_ChgDetRun, "muic-CHGDETRUN" }, |
92 | { MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" }, | 55 | { MAX8997_MUICIRQ_ChgTyp, "muic-CHGTYP" }, |
93 | { MAX8997_MUICIRQ_OVP, "muic-over_voltage" }, | 56 | { MAX8997_MUICIRQ_OVP, "muic-OVP" }, |
57 | }; | ||
58 | |||
59 | /* Define supported cable type */ | ||
60 | enum max8997_muic_acc_type { | ||
61 | MAX8997_MUIC_ADC_GROUND = 0x0, | ||
62 | MAX8997_MUIC_ADC_MHL, /* MHL*/ | ||
63 | MAX8997_MUIC_ADC_REMOTE_S1_BUTTON, | ||
64 | MAX8997_MUIC_ADC_REMOTE_S2_BUTTON, | ||
65 | MAX8997_MUIC_ADC_REMOTE_S3_BUTTON, | ||
66 | MAX8997_MUIC_ADC_REMOTE_S4_BUTTON, | ||
67 | MAX8997_MUIC_ADC_REMOTE_S5_BUTTON, | ||
68 | MAX8997_MUIC_ADC_REMOTE_S6_BUTTON, | ||
69 | MAX8997_MUIC_ADC_REMOTE_S7_BUTTON, | ||
70 | MAX8997_MUIC_ADC_REMOTE_S8_BUTTON, | ||
71 | MAX8997_MUIC_ADC_REMOTE_S9_BUTTON, | ||
72 | MAX8997_MUIC_ADC_REMOTE_S10_BUTTON, | ||
73 | MAX8997_MUIC_ADC_REMOTE_S11_BUTTON, | ||
74 | MAX8997_MUIC_ADC_REMOTE_S12_BUTTON, | ||
75 | MAX8997_MUIC_ADC_RESERVED_ACC_1, | ||
76 | MAX8997_MUIC_ADC_RESERVED_ACC_2, | ||
77 | MAX8997_MUIC_ADC_RESERVED_ACC_3, | ||
78 | MAX8997_MUIC_ADC_RESERVED_ACC_4, | ||
79 | MAX8997_MUIC_ADC_RESERVED_ACC_5, | ||
80 | MAX8997_MUIC_ADC_CEA936_AUDIO, | ||
81 | MAX8997_MUIC_ADC_PHONE_POWERED_DEV, | ||
82 | MAX8997_MUIC_ADC_TTY_CONVERTER, | ||
83 | MAX8997_MUIC_ADC_UART_CABLE, | ||
84 | MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG, | ||
85 | MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF, /* JIG-USB-OFF */ | ||
86 | MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON, /* JIG-USB-ON */ | ||
87 | MAX8997_MUIC_ADC_AV_CABLE_NOLOAD, /* DESKDOCK */ | ||
88 | MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG, | ||
89 | MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF, /* JIG-UART */ | ||
90 | MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON, /* CARDOCK */ | ||
91 | MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE, | ||
92 | MAX8997_MUIC_ADC_OPEN, /* OPEN */ | ||
93 | }; | ||
94 | |||
95 | enum max8997_muic_cable_group { | ||
96 | MAX8997_CABLE_GROUP_ADC = 0, | ||
97 | MAX8997_CABLE_GROUP_ADC_GND, | ||
98 | MAX8997_CABLE_GROUP_CHG, | ||
99 | MAX8997_CABLE_GROUP_VBVOLT, | ||
100 | }; | ||
101 | |||
102 | enum max8997_muic_usb_type { | ||
103 | MAX8997_USB_HOST, | ||
104 | MAX8997_USB_DEVICE, | ||
105 | }; | ||
106 | |||
107 | enum max8997_muic_charger_type { | ||
108 | MAX8997_CHARGER_TYPE_NONE = 0, | ||
109 | MAX8997_CHARGER_TYPE_USB, | ||
110 | MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT, | ||
111 | MAX8997_CHARGER_TYPE_DEDICATED_CHG, | ||
112 | MAX8997_CHARGER_TYPE_500MA, | ||
113 | MAX8997_CHARGER_TYPE_1A, | ||
114 | MAX8997_CHARGER_TYPE_DEAD_BATTERY = 7, | ||
94 | }; | 115 | }; |
95 | 116 | ||
96 | struct max8997_muic_info { | 117 | struct max8997_muic_info { |
97 | struct device *dev; | 118 | struct device *dev; |
98 | struct i2c_client *muic; | 119 | struct i2c_client *muic; |
99 | struct max8997_muic_platform_data *muic_pdata; | 120 | struct extcon_dev *edev; |
121 | int prev_cable_type; | ||
122 | int prev_chg_type; | ||
123 | u8 status[2]; | ||
100 | 124 | ||
101 | int irq; | 125 | int irq; |
102 | struct work_struct irq_work; | 126 | struct work_struct irq_work; |
127 | struct mutex mutex; | ||
103 | 128 | ||
129 | struct max8997_muic_platform_data *muic_pdata; | ||
104 | enum max8997_muic_charger_type pre_charger_type; | 130 | enum max8997_muic_charger_type pre_charger_type; |
105 | int pre_adc; | ||
106 | 131 | ||
107 | struct mutex mutex; | 132 | /* |
133 | * Use delayed workqueue to detect cable state and then | ||
134 | * notify cable state to notifiee/platform through uevent. | ||
135 | * After completing the booting of platform, the extcon provider | ||
136 | * driver should notify cable state to upper layer. | ||
137 | */ | ||
138 | struct delayed_work wq_detcable; | ||
139 | |||
140 | /* | ||
141 | * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB | ||
142 | * h/w path of COMP2/COMN1 on CONTROL1 register. | ||
143 | */ | ||
144 | int path_usb; | ||
145 | int path_uart; | ||
146 | }; | ||
108 | 147 | ||
109 | struct extcon_dev *edev; | 148 | enum { |
149 | EXTCON_CABLE_USB = 0, | ||
150 | EXTCON_CABLE_USB_HOST, | ||
151 | EXTCON_CABLE_TA, | ||
152 | EXTCON_CABLE_FAST_CHARGER, | ||
153 | EXTCON_CABLE_SLOW_CHARGER, | ||
154 | EXTCON_CABLE_CHARGE_DOWNSTREAM, | ||
155 | EXTCON_CABLE_MHL, | ||
156 | EXTCON_CABLE_DOCK_DESK, | ||
157 | EXTCON_CABLE_DOCK_CARD, | ||
158 | EXTCON_CABLE_JIG, | ||
159 | |||
160 | _EXTCON_CABLE_NUM, | ||
110 | }; | 161 | }; |
111 | 162 | ||
112 | const char *max8997_extcon_cable[] = { | 163 | static const char *max8997_extcon_cable[] = { |
113 | [0] = "USB", | 164 | [EXTCON_CABLE_USB] = "USB", |
114 | [1] = "USB-Host", | 165 | [EXTCON_CABLE_USB_HOST] = "USB-Host", |
115 | [2] = "TA", | 166 | [EXTCON_CABLE_TA] = "TA", |
116 | [3] = "Fast-charger", | 167 | [EXTCON_CABLE_FAST_CHARGER] = "Fast-charger", |
117 | [4] = "Slow-charger", | 168 | [EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger", |
118 | [5] = "Charge-downstream", | 169 | [EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream", |
119 | [6] = "MHL", | 170 | [EXTCON_CABLE_MHL] = "MHL", |
120 | [7] = "Dock-desk", | 171 | [EXTCON_CABLE_DOCK_DESK] = "Dock-Desk", |
121 | [8] = "Dock-card", | 172 | [EXTCON_CABLE_DOCK_CARD] = "Dock-Card", |
122 | [9] = "JIG", | 173 | [EXTCON_CABLE_JIG] = "JIG", |
123 | 174 | ||
124 | NULL, | 175 | NULL, |
125 | }; | 176 | }; |
126 | 177 | ||
178 | /* | ||
179 | * max8997_muic_set_debounce_time - Set the debounce time of ADC | ||
180 | * @info: the instance including private data of max8997 MUIC | ||
181 | * @time: the debounce time of ADC | ||
182 | */ | ||
183 | static int max8997_muic_set_debounce_time(struct max8997_muic_info *info, | ||
184 | enum max8997_muic_adc_debounce_time time) | ||
185 | { | ||
186 | int ret; | ||
187 | |||
188 | switch (time) { | ||
189 | case ADC_DEBOUNCE_TIME_0_5MS: | ||
190 | case ADC_DEBOUNCE_TIME_10MS: | ||
191 | case ADC_DEBOUNCE_TIME_25MS: | ||
192 | case ADC_DEBOUNCE_TIME_38_62MS: | ||
193 | ret = max8997_update_reg(info->muic, | ||
194 | MAX8997_MUIC_REG_CONTROL3, | ||
195 | time << CONTROL3_ADCDBSET_SHIFT, | ||
196 | CONTROL3_ADCDBSET_MASK); | ||
197 | if (ret) { | ||
198 | dev_err(info->dev, "failed to set ADC debounce time\n"); | ||
199 | return -EAGAIN; | ||
200 | } | ||
201 | break; | ||
202 | default: | ||
203 | dev_err(info->dev, "invalid ADC debounce time\n"); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | }; | ||
209 | |||
210 | /* | ||
211 | * max8997_muic_set_path - Set hardware line according to attached cable | ||
212 | * @info: the instance including private data of max8997 MUIC | ||
213 | * @value: the path according to attached cable | ||
214 | * @attached: the state of cable (true:attached, false:detached) | ||
215 | * | ||
216 | * The max8997 MUIC device share outside H/W line among a varity of cables, | ||
217 | * so this function set internal path of H/W line according to the type of | ||
218 | * attached cable. | ||
219 | */ | ||
220 | static int max8997_muic_set_path(struct max8997_muic_info *info, | ||
221 | u8 val, bool attached) | ||
222 | { | ||
223 | int ret = 0; | ||
224 | u8 ctrl1, ctrl2 = 0; | ||
225 | |||
226 | if (attached) | ||
227 | ctrl1 = val; | ||
228 | else | ||
229 | ctrl1 = CONTROL1_SW_OPEN; | ||
230 | |||
231 | ret = max8997_update_reg(info->muic, | ||
232 | MAX8997_MUIC_REG_CONTROL1, ctrl1, COMP_SW_MASK); | ||
233 | if (ret < 0) { | ||
234 | dev_err(info->dev, "failed to update MUIC register\n"); | ||
235 | return -EAGAIN; | ||
236 | } | ||
237 | |||
238 | if (attached) | ||
239 | ctrl2 |= CONTROL2_CPEN_MASK; /* LowPwr=0, CPEn=1 */ | ||
240 | else | ||
241 | ctrl2 |= CONTROL2_LOWPWR_MASK; /* LowPwr=1, CPEn=0 */ | ||
242 | |||
243 | ret = max8997_update_reg(info->muic, | ||
244 | MAX8997_MUIC_REG_CONTROL2, ctrl2, | ||
245 | CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK); | ||
246 | if (ret < 0) { | ||
247 | dev_err(info->dev, "failed to update MUIC register\n"); | ||
248 | return -EAGAIN; | ||
249 | } | ||
250 | |||
251 | dev_info(info->dev, | ||
252 | "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n", | ||
253 | ctrl1, ctrl2, attached ? "attached" : "detached"); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * max8997_muic_get_cable_type - Return cable type and check cable state | ||
260 | * @info: the instance including private data of max8997 MUIC | ||
261 | * @group: the path according to attached cable | ||
262 | * @attached: store cable state and return | ||
263 | * | ||
264 | * This function check the cable state either attached or detached, | ||
265 | * and then divide precise type of cable according to cable group. | ||
266 | * - MAX8997_CABLE_GROUP_ADC | ||
267 | * - MAX8997_CABLE_GROUP_CHG | ||
268 | */ | ||
269 | static int max8997_muic_get_cable_type(struct max8997_muic_info *info, | ||
270 | enum max8997_muic_cable_group group, bool *attached) | ||
271 | { | ||
272 | int cable_type = 0; | ||
273 | int adc; | ||
274 | int chg_type; | ||
275 | |||
276 | switch (group) { | ||
277 | case MAX8997_CABLE_GROUP_ADC: | ||
278 | /* | ||
279 | * Read ADC value to check cable type and decide cable state | ||
280 | * according to cable type | ||
281 | */ | ||
282 | adc = info->status[0] & STATUS1_ADC_MASK; | ||
283 | adc >>= STATUS1_ADC_SHIFT; | ||
284 | |||
285 | /* | ||
286 | * Check current cable state/cable type and store cable type | ||
287 | * (info->prev_cable_type) for handling cable when cable is | ||
288 | * detached. | ||
289 | */ | ||
290 | if (adc == MAX8997_MUIC_ADC_OPEN) { | ||
291 | *attached = false; | ||
292 | |||
293 | cable_type = info->prev_cable_type; | ||
294 | info->prev_cable_type = MAX8997_MUIC_ADC_OPEN; | ||
295 | } else { | ||
296 | *attached = true; | ||
297 | |||
298 | cable_type = info->prev_cable_type = adc; | ||
299 | } | ||
300 | break; | ||
301 | case MAX8997_CABLE_GROUP_CHG: | ||
302 | /* | ||
303 | * Read charger type to check cable type and decide cable state | ||
304 | * according to type of charger cable. | ||
305 | */ | ||
306 | chg_type = info->status[1] & STATUS2_CHGTYP_MASK; | ||
307 | chg_type >>= STATUS2_CHGTYP_SHIFT; | ||
308 | |||
309 | if (chg_type == MAX8997_CHARGER_TYPE_NONE) { | ||
310 | *attached = false; | ||
311 | |||
312 | cable_type = info->prev_chg_type; | ||
313 | info->prev_chg_type = MAX8997_CHARGER_TYPE_NONE; | ||
314 | } else { | ||
315 | *attached = true; | ||
316 | |||
317 | /* | ||
318 | * Check current cable state/cable type and store cable | ||
319 | * type(info->prev_chg_type) for handling cable when | ||
320 | * charger cable is detached. | ||
321 | */ | ||
322 | cable_type = info->prev_chg_type = chg_type; | ||
323 | } | ||
324 | |||
325 | break; | ||
326 | default: | ||
327 | dev_err(info->dev, "Unknown cable group (%d)\n", group); | ||
328 | cable_type = -EINVAL; | ||
329 | break; | ||
330 | } | ||
331 | |||
332 | return cable_type; | ||
333 | } | ||
334 | |||
127 | static int max8997_muic_handle_usb(struct max8997_muic_info *info, | 335 | static int max8997_muic_handle_usb(struct max8997_muic_info *info, |
128 | enum max8997_muic_usb_type usb_type, bool attached) | 336 | enum max8997_muic_usb_type usb_type, bool attached) |
129 | { | 337 | { |
130 | int ret = 0; | 338 | int ret = 0; |
131 | 339 | ||
132 | if (usb_type == MAX8997_USB_HOST) { | 340 | if (usb_type == MAX8997_USB_HOST) { |
133 | /* switch to USB */ | 341 | ret = max8997_muic_set_path(info, info->path_usb, attached); |
134 | ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, | 342 | if (ret < 0) { |
135 | attached ? MAX8997_SW_USB : MAX8997_SW_OPEN, | ||
136 | SW_MASK); | ||
137 | if (ret) { | ||
138 | dev_err(info->dev, "failed to update muic register\n"); | 343 | dev_err(info->dev, "failed to update muic register\n"); |
139 | goto out; | 344 | return ret; |
140 | } | 345 | } |
141 | } | 346 | } |
142 | 347 | ||
@@ -148,41 +353,39 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info, | |||
148 | extcon_set_cable_state(info->edev, "USB", attached); | 353 | extcon_set_cable_state(info->edev, "USB", attached); |
149 | break; | 354 | break; |
150 | default: | 355 | default: |
151 | ret = -EINVAL; | 356 | dev_err(info->dev, "failed to detect %s usb cable\n", |
152 | break; | 357 | attached ? "attached" : "detached"); |
358 | return -EINVAL; | ||
153 | } | 359 | } |
154 | 360 | ||
155 | out: | 361 | return 0; |
156 | return ret; | ||
157 | } | 362 | } |
158 | 363 | ||
159 | static int max8997_muic_handle_dock(struct max8997_muic_info *info, | 364 | static int max8997_muic_handle_dock(struct max8997_muic_info *info, |
160 | int adc, bool attached) | 365 | int cable_type, bool attached) |
161 | { | 366 | { |
162 | int ret = 0; | 367 | int ret = 0; |
163 | 368 | ||
164 | /* switch to AUDIO */ | 369 | ret = max8997_muic_set_path(info, CONTROL1_SW_AUDIO, attached); |
165 | ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, | ||
166 | attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN, | ||
167 | SW_MASK); | ||
168 | if (ret) { | 370 | if (ret) { |
169 | dev_err(info->dev, "failed to update muic register\n"); | 371 | dev_err(info->dev, "failed to update muic register\n"); |
170 | goto out; | 372 | return ret; |
171 | } | 373 | } |
172 | 374 | ||
173 | switch (adc) { | 375 | switch (cable_type) { |
174 | case MAX8997_ADC_DESKDOCK: | 376 | case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD: |
175 | extcon_set_cable_state(info->edev, "Dock-desk", attached); | 377 | extcon_set_cable_state(info->edev, "Dock-desk", attached); |
176 | break; | 378 | break; |
177 | case MAX8997_ADC_CARDOCK: | 379 | case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON: |
178 | extcon_set_cable_state(info->edev, "Dock-card", attached); | 380 | extcon_set_cable_state(info->edev, "Dock-card", attached); |
179 | break; | 381 | break; |
180 | default: | 382 | default: |
181 | ret = -EINVAL; | 383 | dev_err(info->dev, "failed to detect %s dock device\n", |
182 | break; | 384 | attached ? "attached" : "detached"); |
385 | return -EINVAL; | ||
183 | } | 386 | } |
184 | out: | 387 | |
185 | return ret; | 388 | return 0; |
186 | } | 389 | } |
187 | 390 | ||
188 | static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, | 391 | static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, |
@@ -191,199 +394,188 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, | |||
191 | int ret = 0; | 394 | int ret = 0; |
192 | 395 | ||
193 | /* switch to UART */ | 396 | /* switch to UART */ |
194 | ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1, | 397 | ret = max8997_muic_set_path(info, info->path_uart, attached); |
195 | attached ? MAX8997_SW_UART : MAX8997_SW_OPEN, | ||
196 | SW_MASK); | ||
197 | if (ret) { | 398 | if (ret) { |
198 | dev_err(info->dev, "failed to update muic register\n"); | 399 | dev_err(info->dev, "failed to update muic register\n"); |
199 | goto out; | 400 | return -EINVAL; |
200 | } | 401 | } |
201 | 402 | ||
202 | extcon_set_cable_state(info->edev, "JIG", attached); | 403 | extcon_set_cable_state(info->edev, "JIG", attached); |
203 | out: | ||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info) | ||
208 | { | ||
209 | int ret = 0; | ||
210 | 404 | ||
211 | switch (info->pre_adc) { | 405 | return 0; |
212 | case MAX8997_ADC_GROUND: | ||
213 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false); | ||
214 | break; | ||
215 | case MAX8997_ADC_MHL: | ||
216 | extcon_set_cable_state(info->edev, "MHL", false); | ||
217 | break; | ||
218 | case MAX8997_ADC_JIG_USB_1: | ||
219 | case MAX8997_ADC_JIG_USB_2: | ||
220 | ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false); | ||
221 | break; | ||
222 | case MAX8997_ADC_DESKDOCK: | ||
223 | case MAX8997_ADC_CARDOCK: | ||
224 | ret = max8997_muic_handle_dock(info, info->pre_adc, false); | ||
225 | break; | ||
226 | case MAX8997_ADC_JIG_UART: | ||
227 | ret = max8997_muic_handle_jig_uart(info, false); | ||
228 | break; | ||
229 | default: | ||
230 | break; | ||
231 | } | ||
232 | |||
233 | return ret; | ||
234 | } | 406 | } |
235 | 407 | ||
236 | static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc) | 408 | static int max8997_muic_adc_handler(struct max8997_muic_info *info) |
237 | { | 409 | { |
410 | int cable_type; | ||
411 | bool attached; | ||
238 | int ret = 0; | 412 | int ret = 0; |
239 | 413 | ||
240 | switch (adc) { | 414 | /* Check cable state which is either detached or attached */ |
241 | case MAX8997_ADC_GROUND: | 415 | cable_type = max8997_muic_get_cable_type(info, |
242 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true); | 416 | MAX8997_CABLE_GROUP_ADC, &attached); |
243 | break; | 417 | |
244 | case MAX8997_ADC_MHL: | 418 | switch (cable_type) { |
245 | extcon_set_cable_state(info->edev, "MHL", true); | 419 | case MAX8997_MUIC_ADC_GROUND: |
246 | break; | 420 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, attached); |
247 | case MAX8997_ADC_JIG_USB_1: | 421 | if (ret < 0) |
248 | case MAX8997_ADC_JIG_USB_2: | 422 | return ret; |
249 | ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true); | 423 | break; |
250 | break; | 424 | case MAX8997_MUIC_ADC_MHL: |
251 | case MAX8997_ADC_DESKDOCK: | 425 | extcon_set_cable_state(info->edev, "MHL", attached); |
252 | case MAX8997_ADC_CARDOCK: | 426 | break; |
253 | ret = max8997_muic_handle_dock(info, adc, true); | 427 | case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF: |
254 | break; | 428 | case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON: |
255 | case MAX8997_ADC_JIG_UART: | 429 | ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, attached); |
256 | ret = max8997_muic_handle_jig_uart(info, true); | 430 | if (ret < 0) |
257 | break; | 431 | return ret; |
258 | case MAX8997_ADC_OPEN: | 432 | break; |
259 | ret = max8997_muic_handle_adc_detach(info); | 433 | case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD: |
260 | break; | 434 | case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON: |
261 | default: | 435 | ret = max8997_muic_handle_dock(info, cable_type, attached); |
262 | ret = -EINVAL; | 436 | if (ret < 0) |
263 | goto out; | 437 | return ret; |
264 | } | 438 | break; |
265 | 439 | case MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF: | |
266 | info->pre_adc = adc; | 440 | ret = max8997_muic_handle_jig_uart(info, attached); |
267 | out: | 441 | break; |
268 | return ret; | 442 | case MAX8997_MUIC_ADC_REMOTE_S1_BUTTON: |
269 | } | 443 | case MAX8997_MUIC_ADC_REMOTE_S2_BUTTON: |
270 | 444 | case MAX8997_MUIC_ADC_REMOTE_S3_BUTTON: | |
271 | static int max8997_muic_handle_charger_type_detach( | 445 | case MAX8997_MUIC_ADC_REMOTE_S4_BUTTON: |
272 | struct max8997_muic_info *info) | 446 | case MAX8997_MUIC_ADC_REMOTE_S5_BUTTON: |
273 | { | 447 | case MAX8997_MUIC_ADC_REMOTE_S6_BUTTON: |
274 | switch (info->pre_charger_type) { | 448 | case MAX8997_MUIC_ADC_REMOTE_S7_BUTTON: |
275 | case MAX8997_CHARGER_TYPE_USB: | 449 | case MAX8997_MUIC_ADC_REMOTE_S8_BUTTON: |
276 | extcon_set_cable_state(info->edev, "USB", false); | 450 | case MAX8997_MUIC_ADC_REMOTE_S9_BUTTON: |
277 | break; | 451 | case MAX8997_MUIC_ADC_REMOTE_S10_BUTTON: |
278 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: | 452 | case MAX8997_MUIC_ADC_REMOTE_S11_BUTTON: |
279 | extcon_set_cable_state(info->edev, "Charge-downstream", false); | 453 | case MAX8997_MUIC_ADC_REMOTE_S12_BUTTON: |
280 | break; | 454 | case MAX8997_MUIC_ADC_RESERVED_ACC_1: |
281 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: | 455 | case MAX8997_MUIC_ADC_RESERVED_ACC_2: |
282 | extcon_set_cable_state(info->edev, "TA", false); | 456 | case MAX8997_MUIC_ADC_RESERVED_ACC_3: |
283 | break; | 457 | case MAX8997_MUIC_ADC_RESERVED_ACC_4: |
284 | case MAX8997_CHARGER_TYPE_500MA: | 458 | case MAX8997_MUIC_ADC_RESERVED_ACC_5: |
285 | extcon_set_cable_state(info->edev, "Slow-charger", false); | 459 | case MAX8997_MUIC_ADC_CEA936_AUDIO: |
286 | break; | 460 | case MAX8997_MUIC_ADC_PHONE_POWERED_DEV: |
287 | case MAX8997_CHARGER_TYPE_1A: | 461 | case MAX8997_MUIC_ADC_TTY_CONVERTER: |
288 | extcon_set_cable_state(info->edev, "Fast-charger", false); | 462 | case MAX8997_MUIC_ADC_UART_CABLE: |
289 | break; | 463 | case MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG: |
464 | case MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG: | ||
465 | case MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE: | ||
466 | /* | ||
467 | * This cable isn't used in general case if it is specially | ||
468 | * needed to detect additional cable, should implement | ||
469 | * proper operation when this cable is attached/detached. | ||
470 | */ | ||
471 | dev_info(info->dev, | ||
472 | "cable is %s but it isn't used (type:0x%x)\n", | ||
473 | attached ? "attached" : "detached", cable_type); | ||
474 | return -EAGAIN; | ||
290 | default: | 475 | default: |
476 | dev_err(info->dev, | ||
477 | "failed to detect %s unknown cable (type:0x%x)\n", | ||
478 | attached ? "attached" : "detached", cable_type); | ||
291 | return -EINVAL; | 479 | return -EINVAL; |
292 | break; | ||
293 | } | 480 | } |
294 | 481 | ||
295 | return 0; | 482 | return 0; |
296 | } | 483 | } |
297 | 484 | ||
298 | static int max8997_muic_handle_charger_type(struct max8997_muic_info *info, | 485 | static int max8997_muic_chg_handler(struct max8997_muic_info *info) |
299 | enum max8997_muic_charger_type charger_type) | ||
300 | { | 486 | { |
301 | u8 adc; | 487 | int chg_type; |
302 | int ret; | 488 | bool attached; |
489 | int adc; | ||
303 | 490 | ||
304 | ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc); | 491 | chg_type = max8997_muic_get_cable_type(info, |
305 | if (ret) { | 492 | MAX8997_CABLE_GROUP_CHG, &attached); |
306 | dev_err(info->dev, "failed to read muic register\n"); | ||
307 | goto out; | ||
308 | } | ||
309 | 493 | ||
310 | switch (charger_type) { | 494 | switch (chg_type) { |
311 | case MAX8997_CHARGER_TYPE_NONE: | 495 | case MAX8997_CHARGER_TYPE_NONE: |
312 | ret = max8997_muic_handle_charger_type_detach(info); | ||
313 | break; | 496 | break; |
314 | case MAX8997_CHARGER_TYPE_USB: | 497 | case MAX8997_CHARGER_TYPE_USB: |
315 | if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) { | 498 | adc = info->status[0] & STATUS1_ADC_MASK; |
499 | adc >>= STATUS1_ADC_SHIFT; | ||
500 | |||
501 | if ((adc & STATUS1_ADC_MASK) == MAX8997_MUIC_ADC_OPEN) { | ||
316 | max8997_muic_handle_usb(info, | 502 | max8997_muic_handle_usb(info, |
317 | MAX8997_USB_DEVICE, true); | 503 | MAX8997_USB_DEVICE, attached); |
318 | } | 504 | } |
319 | break; | 505 | break; |
320 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: | 506 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: |
321 | extcon_set_cable_state(info->edev, "Charge-downstream", true); | 507 | extcon_set_cable_state(info->edev, "Charge-downstream", attached); |
322 | break; | 508 | break; |
323 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: | 509 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: |
324 | extcon_set_cable_state(info->edev, "TA", true); | 510 | extcon_set_cable_state(info->edev, "TA", attached); |
325 | break; | 511 | break; |
326 | case MAX8997_CHARGER_TYPE_500MA: | 512 | case MAX8997_CHARGER_TYPE_500MA: |
327 | extcon_set_cable_state(info->edev, "Slow-charger", true); | 513 | extcon_set_cable_state(info->edev, "Slow-charger", attached); |
328 | break; | 514 | break; |
329 | case MAX8997_CHARGER_TYPE_1A: | 515 | case MAX8997_CHARGER_TYPE_1A: |
330 | extcon_set_cable_state(info->edev, "Fast-charger", true); | 516 | extcon_set_cable_state(info->edev, "Fast-charger", attached); |
331 | break; | 517 | break; |
332 | default: | 518 | default: |
333 | ret = -EINVAL; | 519 | dev_err(info->dev, |
334 | goto out; | 520 | "failed to detect %s unknown chg cable (type:0x%x)\n", |
521 | attached ? "attached" : "detached", chg_type); | ||
522 | return -EINVAL; | ||
335 | } | 523 | } |
336 | 524 | ||
337 | info->pre_charger_type = charger_type; | 525 | return 0; |
338 | out: | ||
339 | return ret; | ||
340 | } | 526 | } |
341 | 527 | ||
342 | static void max8997_muic_irq_work(struct work_struct *work) | 528 | static void max8997_muic_irq_work(struct work_struct *work) |
343 | { | 529 | { |
344 | struct max8997_muic_info *info = container_of(work, | 530 | struct max8997_muic_info *info = container_of(work, |
345 | struct max8997_muic_info, irq_work); | 531 | struct max8997_muic_info, irq_work); |
346 | u8 status[2]; | ||
347 | u8 adc, chg_type; | ||
348 | int irq_type = 0; | 532 | int irq_type = 0; |
349 | int i, ret; | 533 | int i, ret; |
350 | 534 | ||
535 | if (!info->edev) | ||
536 | return; | ||
537 | |||
351 | mutex_lock(&info->mutex); | 538 | mutex_lock(&info->mutex); |
352 | 539 | ||
540 | for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++) | ||
541 | if (info->irq == muic_irqs[i].virq) | ||
542 | irq_type = muic_irqs[i].irq; | ||
543 | |||
353 | ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, | 544 | ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, |
354 | 2, status); | 545 | 2, info->status); |
355 | if (ret) { | 546 | if (ret) { |
356 | dev_err(info->dev, "failed to read muic register\n"); | 547 | dev_err(info->dev, "failed to read muic register\n"); |
357 | mutex_unlock(&info->mutex); | 548 | mutex_unlock(&info->mutex); |
358 | return; | 549 | return; |
359 | } | 550 | } |
360 | 551 | ||
361 | dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__, | ||
362 | status[0], status[1]); | ||
363 | |||
364 | for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++) | ||
365 | if (info->irq == muic_irqs[i].virq) | ||
366 | irq_type = muic_irqs[i].irq; | ||
367 | |||
368 | switch (irq_type) { | 552 | switch (irq_type) { |
553 | case MAX8997_MUICIRQ_ADCError: | ||
554 | case MAX8997_MUICIRQ_ADCLow: | ||
369 | case MAX8997_MUICIRQ_ADC: | 555 | case MAX8997_MUICIRQ_ADC: |
370 | adc = status[0] & STATUS1_ADC_MASK; | 556 | /* Handle all of cable except for charger cable */ |
371 | adc >>= STATUS1_ADC_SHIFT; | 557 | ret = max8997_muic_adc_handler(info); |
372 | |||
373 | max8997_muic_handle_adc(info, adc); | ||
374 | break; | 558 | break; |
559 | case MAX8997_MUICIRQ_VBVolt: | ||
560 | case MAX8997_MUICIRQ_DBChg: | ||
561 | case MAX8997_MUICIRQ_DCDTmr: | ||
562 | case MAX8997_MUICIRQ_ChgDetRun: | ||
375 | case MAX8997_MUICIRQ_ChgTyp: | 563 | case MAX8997_MUICIRQ_ChgTyp: |
376 | chg_type = status[1] & STATUS2_CHGTYP_MASK; | 564 | /* Handle charger cable */ |
377 | chg_type >>= STATUS2_CHGTYP_SHIFT; | 565 | ret = max8997_muic_chg_handler(info); |
378 | 566 | break; | |
379 | max8997_muic_handle_charger_type(info, chg_type); | 567 | case MAX8997_MUICIRQ_OVP: |
380 | break; | 568 | break; |
381 | default: | 569 | default: |
382 | dev_info(info->dev, "misc interrupt: irq %d occurred\n", | 570 | dev_info(info->dev, "misc interrupt: irq %d occurred\n", |
383 | irq_type); | 571 | irq_type); |
384 | break; | 572 | mutex_unlock(&info->mutex); |
573 | return; | ||
385 | } | 574 | } |
386 | 575 | ||
576 | if (ret < 0) | ||
577 | dev_err(info->dev, "failed to handle MUIC interrupt\n"); | ||
578 | |||
387 | mutex_unlock(&info->mutex); | 579 | mutex_unlock(&info->mutex); |
388 | 580 | ||
389 | return; | 581 | return; |
@@ -401,29 +593,60 @@ static irqreturn_t max8997_muic_irq_handler(int irq, void *data) | |||
401 | return IRQ_HANDLED; | 593 | return IRQ_HANDLED; |
402 | } | 594 | } |
403 | 595 | ||
404 | static void max8997_muic_detect_dev(struct max8997_muic_info *info) | 596 | static int max8997_muic_detect_dev(struct max8997_muic_info *info) |
405 | { | 597 | { |
406 | int ret; | 598 | int ret = 0; |
407 | u8 status[2], adc, chg_type; | 599 | int adc; |
600 | int chg_type; | ||
601 | bool attached; | ||
408 | 602 | ||
409 | ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, | 603 | mutex_lock(&info->mutex); |
410 | 2, status); | 604 | |
605 | /* Read STATUSx register to detect accessory */ | ||
606 | ret = max8997_bulk_read(info->muic, | ||
607 | MAX8997_MUIC_REG_STATUS1, 2, info->status); | ||
411 | if (ret) { | 608 | if (ret) { |
412 | dev_err(info->dev, "failed to read muic register\n"); | 609 | dev_err(info->dev, "failed to read MUIC register\n"); |
413 | return; | 610 | mutex_unlock(&info->mutex); |
611 | return -EINVAL; | ||
414 | } | 612 | } |
415 | 613 | ||
416 | dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n", | 614 | adc = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC, |
417 | status[0], status[1]); | 615 | &attached); |
616 | if (attached && adc != MAX8997_MUIC_ADC_OPEN) { | ||
617 | ret = max8997_muic_adc_handler(info); | ||
618 | if (ret < 0) { | ||
619 | dev_err(info->dev, "Cannot detect ADC cable\n"); | ||
620 | mutex_unlock(&info->mutex); | ||
621 | return ret; | ||
622 | } | ||
623 | } | ||
418 | 624 | ||
419 | adc = status[0] & STATUS1_ADC_MASK; | 625 | chg_type = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_CHG, |
420 | adc >>= STATUS1_ADC_SHIFT; | 626 | &attached); |
627 | if (attached && chg_type != MAX8997_CHARGER_TYPE_NONE) { | ||
628 | ret = max8997_muic_chg_handler(info); | ||
629 | if (ret < 0) { | ||
630 | dev_err(info->dev, "Cannot detect charger cable\n"); | ||
631 | mutex_unlock(&info->mutex); | ||
632 | return ret; | ||
633 | } | ||
634 | } | ||
635 | |||
636 | mutex_unlock(&info->mutex); | ||
637 | |||
638 | return 0; | ||
639 | } | ||
421 | 640 | ||
422 | chg_type = status[1] & STATUS2_CHGTYP_MASK; | 641 | static void max8997_muic_detect_cable_wq(struct work_struct *work) |
423 | chg_type >>= STATUS2_CHGTYP_SHIFT; | 642 | { |
643 | struct max8997_muic_info *info = container_of(to_delayed_work(work), | ||
644 | struct max8997_muic_info, wq_detcable); | ||
645 | int ret; | ||
424 | 646 | ||
425 | max8997_muic_handle_adc(info, adc); | 647 | ret = max8997_muic_detect_dev(info); |
426 | max8997_muic_handle_charger_type(info, chg_type); | 648 | if (ret < 0) |
649 | pr_err("failed to detect cable type\n"); | ||
427 | } | 650 | } |
428 | 651 | ||
429 | static int max8997_muic_probe(struct platform_device *pdev) | 652 | static int max8997_muic_probe(struct platform_device *pdev) |
@@ -431,6 +654,7 @@ static int max8997_muic_probe(struct platform_device *pdev) | |||
431 | struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); | 654 | struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); |
432 | struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev); | 655 | struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev); |
433 | struct max8997_muic_info *info; | 656 | struct max8997_muic_info *info; |
657 | int delay_jiffies; | ||
434 | int ret, i; | 658 | int ret, i; |
435 | 659 | ||
436 | info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_muic_info), | 660 | info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_muic_info), |
@@ -459,8 +683,10 @@ static int max8997_muic_probe(struct platform_device *pdev) | |||
459 | } | 683 | } |
460 | muic_irq->virq = virq; | 684 | muic_irq->virq = virq; |
461 | 685 | ||
462 | ret = request_threaded_irq(virq, NULL, max8997_muic_irq_handler, | 686 | ret = request_threaded_irq(virq, NULL, |
463 | 0, muic_irq->name, info); | 687 | max8997_muic_irq_handler, |
688 | IRQF_NO_SUSPEND, | ||
689 | muic_irq->name, info); | ||
464 | if (ret) { | 690 | if (ret) { |
465 | dev_err(&pdev->dev, | 691 | dev_err(&pdev->dev, |
466 | "failed: irq request (IRQ: %d," | 692 | "failed: irq request (IRQ: %d," |
@@ -496,10 +722,42 @@ static int max8997_muic_probe(struct platform_device *pdev) | |||
496 | } | 722 | } |
497 | } | 723 | } |
498 | 724 | ||
499 | /* Initial device detection */ | 725 | /* |
500 | max8997_muic_detect_dev(info); | 726 | * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB |
727 | * h/w path of COMP2/COMN1 on CONTROL1 register. | ||
728 | */ | ||
729 | if (pdata->muic_pdata->path_uart) | ||
730 | info->path_uart = pdata->muic_pdata->path_uart; | ||
731 | else | ||
732 | info->path_uart = CONTROL1_SW_UART; | ||
733 | |||
734 | if (pdata->muic_pdata->path_usb) | ||
735 | info->path_usb = pdata->muic_pdata->path_usb; | ||
736 | else | ||
737 | info->path_usb = CONTROL1_SW_USB; | ||
738 | |||
739 | /* Set initial path for UART */ | ||
740 | max8997_muic_set_path(info, info->path_uart, true); | ||
741 | |||
742 | /* Set ADC debounce time */ | ||
743 | max8997_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS); | ||
744 | |||
745 | /* | ||
746 | * Detect accessory after completing the initialization of platform | ||
747 | * | ||
748 | * - Use delayed workqueue to detect cable state and then | ||
749 | * notify cable state to notifiee/platform through uevent. | ||
750 | * After completing the booting of platform, the extcon provider | ||
751 | * driver should notify cable state to upper layer. | ||
752 | */ | ||
753 | INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq); | ||
754 | if (pdata->muic_pdata->detcable_delay_ms) | ||
755 | delay_jiffies = msecs_to_jiffies(pdata->muic_pdata->detcable_delay_ms); | ||
756 | else | ||
757 | delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT); | ||
758 | schedule_delayed_work(&info->wq_detcable, delay_jiffies); | ||
501 | 759 | ||
502 | return ret; | 760 | return 0; |
503 | 761 | ||
504 | err_irq: | 762 | err_irq: |
505 | while (--i >= 0) | 763 | while (--i >= 0) |