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) |
