diff options
author | Chanwoo Choi <cw00.choi@samsung.com> | 2013-02-12 22:05:42 -0500 |
---|---|---|
committer | Chanwoo Choi <cw00.choi@samsung.com> | 2013-02-13 17:54:22 -0500 |
commit | f73f6232af9131f7b6fc6e377267e4a441727eb3 (patch) | |
tree | 67282c916730b43330c345f1e16ee29bb0b474b7 /drivers/extcon/extcon-max8997.c | |
parent | 027fcd50500fd87847891d5c2f341c1f002de3e8 (diff) |
extcon: max8997: Consolidate duplicate code for checking ADC/CHG cable type
This patch make max8997_muic_get_cable_type() function to remove
duplicate code for checking ADC/Charger cable type because almost
internal function need to read adc/chg_type value of MUIC register.
Also, remove *_detach() function, extcon-max8997 driver treat
attach/detach operation of cable in max8997_*_handler() function.
Lastly, this patch move defined constant in header file(include/
linux/mfd/max8997.h, max8997-private.h) because defined constant
is only used in the 'extcon-max8997.c'.
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/extcon/extcon-max8997.c')
-rw-r--r-- | drivers/extcon/extcon-max8997.c | 492 |
1 files changed, 323 insertions, 169 deletions
diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 3206daaf8e08..35338a090c06 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c | |||
@@ -44,31 +44,89 @@ struct max8997_muic_irq { | |||
44 | }; | 44 | }; |
45 | 45 | ||
46 | static struct max8997_muic_irq muic_irqs[] = { | 46 | static struct max8997_muic_irq muic_irqs[] = { |
47 | { MAX8997_MUICIRQ_ADCError, "muic-ADC_error" }, | 47 | { MAX8997_MUICIRQ_ADCError, "muic-ADCERROR" }, |
48 | { MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" }, | 48 | { MAX8997_MUICIRQ_ADCLow, "muic-ADCLOW" }, |
49 | { MAX8997_MUICIRQ_ADC, "muic-ADC" }, | 49 | { MAX8997_MUICIRQ_ADC, "muic-ADC" }, |
50 | { MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" }, | 50 | { MAX8997_MUICIRQ_VBVolt, "muic-VBVOLT" }, |
51 | { MAX8997_MUICIRQ_DBChg, "muic-DB_charger" }, | 51 | { MAX8997_MUICIRQ_DBChg, "muic-DBCHG" }, |
52 | { MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" }, | 52 | { MAX8997_MUICIRQ_DCDTmr, "muic-DCDTMR" }, |
53 | { MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" }, | 53 | { MAX8997_MUICIRQ_ChgDetRun, "muic-CHGDETRUN" }, |
54 | { MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" }, | 54 | { MAX8997_MUICIRQ_ChgTyp, "muic-CHGTYP" }, |
55 | { MAX8997_MUICIRQ_OVP, "muic-over_voltage" }, | 55 | { MAX8997_MUICIRQ_OVP, "muic-OVP" }, |
56 | }; | ||
57 | |||
58 | /* Define supported cable type */ | ||
59 | enum max8997_muic_acc_type { | ||
60 | MAX8997_MUIC_ADC_GROUND = 0x0, | ||
61 | MAX8997_MUIC_ADC_MHL, /* MHL*/ | ||
62 | MAX8997_MUIC_ADC_REMOTE_S1_BUTTON, | ||
63 | MAX8997_MUIC_ADC_REMOTE_S2_BUTTON, | ||
64 | MAX8997_MUIC_ADC_REMOTE_S3_BUTTON, | ||
65 | MAX8997_MUIC_ADC_REMOTE_S4_BUTTON, | ||
66 | MAX8997_MUIC_ADC_REMOTE_S5_BUTTON, | ||
67 | MAX8997_MUIC_ADC_REMOTE_S6_BUTTON, | ||
68 | MAX8997_MUIC_ADC_REMOTE_S7_BUTTON, | ||
69 | MAX8997_MUIC_ADC_REMOTE_S8_BUTTON, | ||
70 | MAX8997_MUIC_ADC_REMOTE_S9_BUTTON, | ||
71 | MAX8997_MUIC_ADC_REMOTE_S10_BUTTON, | ||
72 | MAX8997_MUIC_ADC_REMOTE_S11_BUTTON, | ||
73 | MAX8997_MUIC_ADC_REMOTE_S12_BUTTON, | ||
74 | MAX8997_MUIC_ADC_RESERVED_ACC_1, | ||
75 | MAX8997_MUIC_ADC_RESERVED_ACC_2, | ||
76 | MAX8997_MUIC_ADC_RESERVED_ACC_3, | ||
77 | MAX8997_MUIC_ADC_RESERVED_ACC_4, | ||
78 | MAX8997_MUIC_ADC_RESERVED_ACC_5, | ||
79 | MAX8997_MUIC_ADC_CEA936_AUDIO, | ||
80 | MAX8997_MUIC_ADC_PHONE_POWERED_DEV, | ||
81 | MAX8997_MUIC_ADC_TTY_CONVERTER, | ||
82 | MAX8997_MUIC_ADC_UART_CABLE, | ||
83 | MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG, | ||
84 | MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF, /* JIG-USB-OFF */ | ||
85 | MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON, /* JIG-USB-ON */ | ||
86 | MAX8997_MUIC_ADC_AV_CABLE_NOLOAD, /* DESKDOCK */ | ||
87 | MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG, | ||
88 | MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF, /* JIG-UART */ | ||
89 | MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON, /* CARDOCK */ | ||
90 | MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE, | ||
91 | MAX8997_MUIC_ADC_OPEN, /* OPEN */ | ||
92 | }; | ||
93 | |||
94 | enum max8997_muic_cable_group { | ||
95 | MAX8997_CABLE_GROUP_ADC = 0, | ||
96 | MAX8997_CABLE_GROUP_ADC_GND, | ||
97 | MAX8997_CABLE_GROUP_CHG, | ||
98 | MAX8997_CABLE_GROUP_VBVOLT, | ||
99 | }; | ||
100 | |||
101 | enum max8997_muic_usb_type { | ||
102 | MAX8997_USB_HOST, | ||
103 | MAX8997_USB_DEVICE, | ||
104 | }; | ||
105 | |||
106 | enum max8997_muic_charger_type { | ||
107 | MAX8997_CHARGER_TYPE_NONE = 0, | ||
108 | MAX8997_CHARGER_TYPE_USB, | ||
109 | MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT, | ||
110 | MAX8997_CHARGER_TYPE_DEDICATED_CHG, | ||
111 | MAX8997_CHARGER_TYPE_500MA, | ||
112 | MAX8997_CHARGER_TYPE_1A, | ||
113 | MAX8997_CHARGER_TYPE_DEAD_BATTERY = 7, | ||
56 | }; | 114 | }; |
57 | 115 | ||
58 | struct max8997_muic_info { | 116 | struct max8997_muic_info { |
59 | struct device *dev; | 117 | struct device *dev; |
60 | struct i2c_client *muic; | 118 | struct i2c_client *muic; |
61 | struct max8997_muic_platform_data *muic_pdata; | 119 | struct extcon_dev *edev; |
120 | int prev_cable_type; | ||
121 | int prev_chg_type; | ||
122 | u8 status[2]; | ||
62 | 123 | ||
63 | int irq; | 124 | int irq; |
64 | struct work_struct irq_work; | 125 | struct work_struct irq_work; |
65 | |||
66 | enum max8997_muic_charger_type pre_charger_type; | ||
67 | int pre_adc; | ||
68 | |||
69 | struct mutex mutex; | 126 | struct mutex mutex; |
70 | 127 | ||
71 | struct extcon_dev *edev; | 128 | struct max8997_muic_platform_data *muic_pdata; |
129 | enum max8997_muic_charger_type pre_charger_type; | ||
72 | }; | 130 | }; |
73 | 131 | ||
74 | enum { | 132 | enum { |
@@ -181,6 +239,83 @@ static int max8997_muic_set_path(struct max8997_muic_info *info, | |||
181 | return 0; | 239 | return 0; |
182 | } | 240 | } |
183 | 241 | ||
242 | /* | ||
243 | * max8997_muic_get_cable_type - Return cable type and check cable state | ||
244 | * @info: the instance including private data of max8997 MUIC | ||
245 | * @group: the path according to attached cable | ||
246 | * @attached: store cable state and return | ||
247 | * | ||
248 | * This function check the cable state either attached or detached, | ||
249 | * and then divide precise type of cable according to cable group. | ||
250 | * - MAX8997_CABLE_GROUP_ADC | ||
251 | * - MAX8997_CABLE_GROUP_CHG | ||
252 | */ | ||
253 | static int max8997_muic_get_cable_type(struct max8997_muic_info *info, | ||
254 | enum max8997_muic_cable_group group, bool *attached) | ||
255 | { | ||
256 | int cable_type = 0; | ||
257 | int adc; | ||
258 | int chg_type; | ||
259 | |||
260 | switch (group) { | ||
261 | case MAX8997_CABLE_GROUP_ADC: | ||
262 | /* | ||
263 | * Read ADC value to check cable type and decide cable state | ||
264 | * according to cable type | ||
265 | */ | ||
266 | adc = info->status[0] & STATUS1_ADC_MASK; | ||
267 | adc >>= STATUS1_ADC_SHIFT; | ||
268 | |||
269 | /* | ||
270 | * Check current cable state/cable type and store cable type | ||
271 | * (info->prev_cable_type) for handling cable when cable is | ||
272 | * detached. | ||
273 | */ | ||
274 | if (adc == MAX8997_MUIC_ADC_OPEN) { | ||
275 | *attached = false; | ||
276 | |||
277 | cable_type = info->prev_cable_type; | ||
278 | info->prev_cable_type = MAX8997_MUIC_ADC_OPEN; | ||
279 | } else { | ||
280 | *attached = true; | ||
281 | |||
282 | cable_type = info->prev_cable_type = adc; | ||
283 | } | ||
284 | break; | ||
285 | case MAX8997_CABLE_GROUP_CHG: | ||
286 | /* | ||
287 | * Read charger type to check cable type and decide cable state | ||
288 | * according to type of charger cable. | ||
289 | */ | ||
290 | chg_type = info->status[1] & STATUS2_CHGTYP_MASK; | ||
291 | chg_type >>= STATUS2_CHGTYP_SHIFT; | ||
292 | |||
293 | if (chg_type == MAX8997_CHARGER_TYPE_NONE) { | ||
294 | *attached = false; | ||
295 | |||
296 | cable_type = info->prev_chg_type; | ||
297 | info->prev_chg_type = MAX8997_CHARGER_TYPE_NONE; | ||
298 | } else { | ||
299 | *attached = true; | ||
300 | |||
301 | /* | ||
302 | * Check current cable state/cable type and store cable | ||
303 | * type(info->prev_chg_type) for handling cable when | ||
304 | * charger cable is detached. | ||
305 | */ | ||
306 | cable_type = info->prev_chg_type = chg_type; | ||
307 | } | ||
308 | |||
309 | break; | ||
310 | default: | ||
311 | dev_err(info->dev, "Unknown cable group (%d)\n", group); | ||
312 | cable_type = -EINVAL; | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | return cable_type; | ||
317 | } | ||
318 | |||
184 | static int max8997_muic_handle_usb(struct max8997_muic_info *info, | 319 | static int max8997_muic_handle_usb(struct max8997_muic_info *info, |
185 | enum max8997_muic_usb_type usb_type, bool attached) | 320 | enum max8997_muic_usb_type usb_type, bool attached) |
186 | { | 321 | { |
@@ -188,9 +323,9 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info, | |||
188 | 323 | ||
189 | if (usb_type == MAX8997_USB_HOST) { | 324 | if (usb_type == MAX8997_USB_HOST) { |
190 | ret = max8997_muic_set_path(info, CONTROL1_SW_USB, attached); | 325 | ret = max8997_muic_set_path(info, CONTROL1_SW_USB, attached); |
191 | if (ret) { | 326 | if (ret < 0) { |
192 | dev_err(info->dev, "failed to update muic register\n"); | 327 | dev_err(info->dev, "failed to update muic register\n"); |
193 | goto out; | 328 | return ret; |
194 | } | 329 | } |
195 | } | 330 | } |
196 | 331 | ||
@@ -202,38 +337,39 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info, | |||
202 | extcon_set_cable_state(info->edev, "USB", attached); | 337 | extcon_set_cable_state(info->edev, "USB", attached); |
203 | break; | 338 | break; |
204 | default: | 339 | default: |
205 | ret = -EINVAL; | 340 | dev_err(info->dev, "failed to detect %s usb cable\n", |
206 | break; | 341 | attached ? "attached" : "detached"); |
342 | return -EINVAL; | ||
207 | } | 343 | } |
208 | 344 | ||
209 | out: | 345 | return 0; |
210 | return ret; | ||
211 | } | 346 | } |
212 | 347 | ||
213 | static int max8997_muic_handle_dock(struct max8997_muic_info *info, | 348 | static int max8997_muic_handle_dock(struct max8997_muic_info *info, |
214 | int adc, bool attached) | 349 | int cable_type, bool attached) |
215 | { | 350 | { |
216 | int ret = 0; | 351 | int ret = 0; |
217 | 352 | ||
218 | ret = max8997_muic_set_path(info, CONTROL1_SW_AUDIO, attached); | 353 | ret = max8997_muic_set_path(info, CONTROL1_SW_AUDIO, attached); |
219 | if (ret) { | 354 | if (ret) { |
220 | dev_err(info->dev, "failed to update muic register\n"); | 355 | dev_err(info->dev, "failed to update muic register\n"); |
221 | goto out; | 356 | return ret; |
222 | } | 357 | } |
223 | 358 | ||
224 | switch (adc) { | 359 | switch (cable_type) { |
225 | case MAX8997_ADC_DESKDOCK: | 360 | case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD: |
226 | extcon_set_cable_state(info->edev, "Dock-desk", attached); | 361 | extcon_set_cable_state(info->edev, "Dock-desk", attached); |
227 | break; | 362 | break; |
228 | case MAX8997_ADC_CARDOCK: | 363 | case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON: |
229 | extcon_set_cable_state(info->edev, "Dock-card", attached); | 364 | extcon_set_cable_state(info->edev, "Dock-card", attached); |
230 | break; | 365 | break; |
231 | default: | 366 | default: |
232 | ret = -EINVAL; | 367 | dev_err(info->dev, "failed to detect %s dock device\n", |
233 | break; | 368 | attached ? "attached" : "detached"); |
369 | return -EINVAL; | ||
234 | } | 370 | } |
235 | out: | 371 | |
236 | return ret; | 372 | return 0; |
237 | } | 373 | } |
238 | 374 | ||
239 | static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, | 375 | static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, |
@@ -245,193 +381,185 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, | |||
245 | ret = max8997_muic_set_path(info, CONTROL1_SW_UART, attached); | 381 | ret = max8997_muic_set_path(info, CONTROL1_SW_UART, attached); |
246 | if (ret) { | 382 | if (ret) { |
247 | dev_err(info->dev, "failed to update muic register\n"); | 383 | dev_err(info->dev, "failed to update muic register\n"); |
248 | goto out; | 384 | return -EINVAL; |
249 | } | 385 | } |
250 | 386 | ||
251 | extcon_set_cable_state(info->edev, "JIG", attached); | 387 | extcon_set_cable_state(info->edev, "JIG", attached); |
252 | out: | ||
253 | return ret; | ||
254 | } | ||
255 | 388 | ||
256 | static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info) | 389 | return 0; |
257 | { | ||
258 | int ret = 0; | ||
259 | |||
260 | switch (info->pre_adc) { | ||
261 | case MAX8997_ADC_GROUND: | ||
262 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false); | ||
263 | break; | ||
264 | case MAX8997_ADC_MHL: | ||
265 | extcon_set_cable_state(info->edev, "MHL", false); | ||
266 | break; | ||
267 | case MAX8997_ADC_JIG_USB_1: | ||
268 | case MAX8997_ADC_JIG_USB_2: | ||
269 | ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false); | ||
270 | break; | ||
271 | case MAX8997_ADC_DESKDOCK: | ||
272 | case MAX8997_ADC_CARDOCK: | ||
273 | ret = max8997_muic_handle_dock(info, info->pre_adc, false); | ||
274 | break; | ||
275 | case MAX8997_ADC_JIG_UART: | ||
276 | ret = max8997_muic_handle_jig_uart(info, false); | ||
277 | break; | ||
278 | default: | ||
279 | break; | ||
280 | } | ||
281 | |||
282 | return ret; | ||
283 | } | 390 | } |
284 | 391 | ||
285 | static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc) | 392 | static int max8997_muic_adc_handler(struct max8997_muic_info *info) |
286 | { | 393 | { |
394 | int cable_type; | ||
395 | bool attached; | ||
287 | int ret = 0; | 396 | int ret = 0; |
288 | 397 | ||
289 | switch (adc) { | 398 | /* Check cable state which is either detached or attached */ |
290 | case MAX8997_ADC_GROUND: | 399 | cable_type = max8997_muic_get_cable_type(info, |
291 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true); | 400 | MAX8997_CABLE_GROUP_ADC, &attached); |
292 | break; | 401 | |
293 | case MAX8997_ADC_MHL: | 402 | switch (cable_type) { |
294 | extcon_set_cable_state(info->edev, "MHL", true); | 403 | case MAX8997_MUIC_ADC_GROUND: |
295 | break; | 404 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, attached); |
296 | case MAX8997_ADC_JIG_USB_1: | 405 | if (ret < 0) |
297 | case MAX8997_ADC_JIG_USB_2: | 406 | return ret; |
298 | ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true); | 407 | break; |
299 | break; | 408 | case MAX8997_MUIC_ADC_MHL: |
300 | case MAX8997_ADC_DESKDOCK: | 409 | extcon_set_cable_state(info->edev, "MHL", attached); |
301 | case MAX8997_ADC_CARDOCK: | 410 | break; |
302 | ret = max8997_muic_handle_dock(info, adc, true); | 411 | case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF: |
303 | break; | 412 | case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON: |
304 | case MAX8997_ADC_JIG_UART: | 413 | ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, attached); |
305 | ret = max8997_muic_handle_jig_uart(info, true); | 414 | if (ret < 0) |
306 | break; | 415 | return ret; |
307 | case MAX8997_ADC_OPEN: | 416 | break; |
308 | ret = max8997_muic_handle_adc_detach(info); | 417 | case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD: |
309 | break; | 418 | case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON: |
310 | default: | 419 | ret = max8997_muic_handle_dock(info, cable_type, attached); |
311 | ret = -EINVAL; | 420 | if (ret < 0) |
312 | goto out; | 421 | return ret; |
313 | } | 422 | break; |
314 | 423 | case MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF: | |
315 | info->pre_adc = adc; | 424 | ret = max8997_muic_handle_jig_uart(info, attached); |
316 | out: | 425 | break; |
317 | return ret; | 426 | case MAX8997_MUIC_ADC_REMOTE_S1_BUTTON: |
318 | } | 427 | case MAX8997_MUIC_ADC_REMOTE_S2_BUTTON: |
319 | 428 | case MAX8997_MUIC_ADC_REMOTE_S3_BUTTON: | |
320 | static int max8997_muic_handle_charger_type_detach( | 429 | case MAX8997_MUIC_ADC_REMOTE_S4_BUTTON: |
321 | struct max8997_muic_info *info) | 430 | case MAX8997_MUIC_ADC_REMOTE_S5_BUTTON: |
322 | { | 431 | case MAX8997_MUIC_ADC_REMOTE_S6_BUTTON: |
323 | switch (info->pre_charger_type) { | 432 | case MAX8997_MUIC_ADC_REMOTE_S7_BUTTON: |
324 | case MAX8997_CHARGER_TYPE_USB: | 433 | case MAX8997_MUIC_ADC_REMOTE_S8_BUTTON: |
325 | extcon_set_cable_state(info->edev, "USB", false); | 434 | case MAX8997_MUIC_ADC_REMOTE_S9_BUTTON: |
326 | break; | 435 | case MAX8997_MUIC_ADC_REMOTE_S10_BUTTON: |
327 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: | 436 | case MAX8997_MUIC_ADC_REMOTE_S11_BUTTON: |
328 | extcon_set_cable_state(info->edev, "Charge-downstream", false); | 437 | case MAX8997_MUIC_ADC_REMOTE_S12_BUTTON: |
329 | break; | 438 | case MAX8997_MUIC_ADC_RESERVED_ACC_1: |
330 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: | 439 | case MAX8997_MUIC_ADC_RESERVED_ACC_2: |
331 | extcon_set_cable_state(info->edev, "TA", false); | 440 | case MAX8997_MUIC_ADC_RESERVED_ACC_3: |
332 | break; | 441 | case MAX8997_MUIC_ADC_RESERVED_ACC_4: |
333 | case MAX8997_CHARGER_TYPE_500MA: | 442 | case MAX8997_MUIC_ADC_RESERVED_ACC_5: |
334 | extcon_set_cable_state(info->edev, "Slow-charger", false); | 443 | case MAX8997_MUIC_ADC_CEA936_AUDIO: |
335 | break; | 444 | case MAX8997_MUIC_ADC_PHONE_POWERED_DEV: |
336 | case MAX8997_CHARGER_TYPE_1A: | 445 | case MAX8997_MUIC_ADC_TTY_CONVERTER: |
337 | extcon_set_cable_state(info->edev, "Fast-charger", false); | 446 | case MAX8997_MUIC_ADC_UART_CABLE: |
338 | break; | 447 | case MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG: |
448 | case MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG: | ||
449 | case MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE: | ||
450 | /* | ||
451 | * This cable isn't used in general case if it is specially | ||
452 | * needed to detect additional cable, should implement | ||
453 | * proper operation when this cable is attached/detached. | ||
454 | */ | ||
455 | dev_info(info->dev, | ||
456 | "cable is %s but it isn't used (type:0x%x)\n", | ||
457 | attached ? "attached" : "detached", cable_type); | ||
458 | return -EAGAIN; | ||
339 | default: | 459 | default: |
460 | dev_err(info->dev, | ||
461 | "failed to detect %s unknown cable (type:0x%x)\n", | ||
462 | attached ? "attached" : "detached", cable_type); | ||
340 | return -EINVAL; | 463 | return -EINVAL; |
341 | } | 464 | } |
342 | 465 | ||
343 | return 0; | 466 | return 0; |
344 | } | 467 | } |
345 | 468 | ||
346 | static int max8997_muic_handle_charger_type(struct max8997_muic_info *info, | 469 | static int max8997_muic_chg_handler(struct max8997_muic_info *info) |
347 | enum max8997_muic_charger_type charger_type) | ||
348 | { | 470 | { |
349 | u8 adc; | 471 | int chg_type; |
350 | int ret; | 472 | bool attached; |
473 | int adc; | ||
351 | 474 | ||
352 | ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc); | 475 | chg_type = max8997_muic_get_cable_type(info, |
353 | if (ret) { | 476 | MAX8997_CABLE_GROUP_CHG, &attached); |
354 | dev_err(info->dev, "failed to read muic register\n"); | ||
355 | goto out; | ||
356 | } | ||
357 | 477 | ||
358 | switch (charger_type) { | 478 | switch (chg_type) { |
359 | case MAX8997_CHARGER_TYPE_NONE: | 479 | case MAX8997_CHARGER_TYPE_NONE: |
360 | ret = max8997_muic_handle_charger_type_detach(info); | ||
361 | break; | 480 | break; |
362 | case MAX8997_CHARGER_TYPE_USB: | 481 | case MAX8997_CHARGER_TYPE_USB: |
363 | if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) { | 482 | adc = info->status[0] & STATUS1_ADC_MASK; |
483 | adc >>= STATUS1_ADC_SHIFT; | ||
484 | |||
485 | if ((adc & STATUS1_ADC_MASK) == MAX8997_MUIC_ADC_OPEN) { | ||
364 | max8997_muic_handle_usb(info, | 486 | max8997_muic_handle_usb(info, |
365 | MAX8997_USB_DEVICE, true); | 487 | MAX8997_USB_DEVICE, attached); |
366 | } | 488 | } |
367 | break; | 489 | break; |
368 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: | 490 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: |
369 | extcon_set_cable_state(info->edev, "Charge-downstream", true); | 491 | extcon_set_cable_state(info->edev, "Charge-downstream", attached); |
370 | break; | 492 | break; |
371 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: | 493 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: |
372 | extcon_set_cable_state(info->edev, "TA", true); | 494 | extcon_set_cable_state(info->edev, "TA", attached); |
373 | break; | 495 | break; |
374 | case MAX8997_CHARGER_TYPE_500MA: | 496 | case MAX8997_CHARGER_TYPE_500MA: |
375 | extcon_set_cable_state(info->edev, "Slow-charger", true); | 497 | extcon_set_cable_state(info->edev, "Slow-charger", attached); |
376 | break; | 498 | break; |
377 | case MAX8997_CHARGER_TYPE_1A: | 499 | case MAX8997_CHARGER_TYPE_1A: |
378 | extcon_set_cable_state(info->edev, "Fast-charger", true); | 500 | extcon_set_cable_state(info->edev, "Fast-charger", attached); |
379 | break; | 501 | break; |
380 | default: | 502 | default: |
381 | ret = -EINVAL; | 503 | dev_err(info->dev, |
382 | goto out; | 504 | "failed to detect %s unknown chg cable (type:0x%x)\n", |
505 | attached ? "attached" : "detached", chg_type); | ||
506 | return -EINVAL; | ||
383 | } | 507 | } |
384 | 508 | ||
385 | info->pre_charger_type = charger_type; | 509 | return 0; |
386 | out: | ||
387 | return ret; | ||
388 | } | 510 | } |
389 | 511 | ||
390 | static void max8997_muic_irq_work(struct work_struct *work) | 512 | static void max8997_muic_irq_work(struct work_struct *work) |
391 | { | 513 | { |
392 | struct max8997_muic_info *info = container_of(work, | 514 | struct max8997_muic_info *info = container_of(work, |
393 | struct max8997_muic_info, irq_work); | 515 | struct max8997_muic_info, irq_work); |
394 | u8 status[2]; | ||
395 | u8 adc, chg_type; | ||
396 | int irq_type = 0; | 516 | int irq_type = 0; |
397 | int i, ret; | 517 | int i, ret; |
398 | 518 | ||
519 | if (!info->edev) | ||
520 | return; | ||
521 | |||
399 | mutex_lock(&info->mutex); | 522 | mutex_lock(&info->mutex); |
400 | 523 | ||
524 | for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++) | ||
525 | if (info->irq == muic_irqs[i].virq) | ||
526 | irq_type = muic_irqs[i].irq; | ||
527 | |||
401 | ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, | 528 | ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, |
402 | 2, status); | 529 | 2, info->status); |
403 | if (ret) { | 530 | if (ret) { |
404 | dev_err(info->dev, "failed to read muic register\n"); | 531 | dev_err(info->dev, "failed to read muic register\n"); |
405 | mutex_unlock(&info->mutex); | 532 | mutex_unlock(&info->mutex); |
406 | return; | 533 | return; |
407 | } | 534 | } |
408 | 535 | ||
409 | dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__, | ||
410 | status[0], status[1]); | ||
411 | |||
412 | for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++) | ||
413 | if (info->irq == muic_irqs[i].virq) | ||
414 | irq_type = muic_irqs[i].irq; | ||
415 | |||
416 | switch (irq_type) { | 536 | switch (irq_type) { |
537 | case MAX8997_MUICIRQ_ADCError: | ||
538 | case MAX8997_MUICIRQ_ADCLow: | ||
417 | case MAX8997_MUICIRQ_ADC: | 539 | case MAX8997_MUICIRQ_ADC: |
418 | adc = status[0] & STATUS1_ADC_MASK; | 540 | /* Handle all of cable except for charger cable */ |
419 | adc >>= STATUS1_ADC_SHIFT; | 541 | ret = max8997_muic_adc_handler(info); |
420 | |||
421 | max8997_muic_handle_adc(info, adc); | ||
422 | break; | 542 | break; |
543 | case MAX8997_MUICIRQ_VBVolt: | ||
544 | case MAX8997_MUICIRQ_DBChg: | ||
545 | case MAX8997_MUICIRQ_DCDTmr: | ||
546 | case MAX8997_MUICIRQ_ChgDetRun: | ||
423 | case MAX8997_MUICIRQ_ChgTyp: | 547 | case MAX8997_MUICIRQ_ChgTyp: |
424 | chg_type = status[1] & STATUS2_CHGTYP_MASK; | 548 | /* Handle charger cable */ |
425 | chg_type >>= STATUS2_CHGTYP_SHIFT; | 549 | ret = max8997_muic_chg_handler(info); |
426 | 550 | break; | |
427 | max8997_muic_handle_charger_type(info, chg_type); | 551 | case MAX8997_MUICIRQ_OVP: |
428 | break; | 552 | break; |
429 | default: | 553 | default: |
430 | dev_info(info->dev, "misc interrupt: irq %d occurred\n", | 554 | dev_info(info->dev, "misc interrupt: irq %d occurred\n", |
431 | irq_type); | 555 | irq_type); |
432 | break; | 556 | mutex_unlock(&info->mutex); |
557 | return; | ||
433 | } | 558 | } |
434 | 559 | ||
560 | if (ret < 0) | ||
561 | dev_err(info->dev, "failed to handle MUIC interrupt\n"); | ||
562 | |||
435 | mutex_unlock(&info->mutex); | 563 | mutex_unlock(&info->mutex); |
436 | 564 | ||
437 | return; | 565 | return; |
@@ -449,29 +577,49 @@ static irqreturn_t max8997_muic_irq_handler(int irq, void *data) | |||
449 | return IRQ_HANDLED; | 577 | return IRQ_HANDLED; |
450 | } | 578 | } |
451 | 579 | ||
452 | static void max8997_muic_detect_dev(struct max8997_muic_info *info) | 580 | static int max8997_muic_detect_dev(struct max8997_muic_info *info) |
453 | { | 581 | { |
454 | int ret; | 582 | int ret = 0; |
455 | u8 status[2], adc, chg_type; | 583 | int adc; |
584 | int chg_type; | ||
585 | bool attached; | ||
456 | 586 | ||
457 | ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, | 587 | mutex_lock(&info->mutex); |
458 | 2, status); | 588 | |
589 | /* Read STATUSx register to detect accessory */ | ||
590 | ret = max8997_bulk_read(info->muic, | ||
591 | MAX8997_MUIC_REG_STATUS1, 2, info->status); | ||
459 | if (ret) { | 592 | if (ret) { |
460 | dev_err(info->dev, "failed to read muic register\n"); | 593 | dev_err(info->dev, "failed to read MUIC register\n"); |
461 | return; | 594 | mutex_unlock(&info->mutex); |
595 | return -EINVAL; | ||
462 | } | 596 | } |
463 | 597 | ||
464 | dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n", | 598 | adc = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC, |
465 | status[0], status[1]); | 599 | &attached); |
600 | if (attached && adc != MAX8997_MUIC_ADC_OPEN) { | ||
601 | ret = max8997_muic_adc_handler(info); | ||
602 | if (ret < 0) { | ||
603 | dev_err(info->dev, "Cannot detect ADC cable\n"); | ||
604 | mutex_unlock(&info->mutex); | ||
605 | return ret; | ||
606 | } | ||
607 | } | ||
466 | 608 | ||
467 | adc = status[0] & STATUS1_ADC_MASK; | 609 | chg_type = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_CHG, |
468 | adc >>= STATUS1_ADC_SHIFT; | 610 | &attached); |
611 | if (attached && chg_type != MAX8997_CHARGER_TYPE_NONE) { | ||
612 | ret = max8997_muic_chg_handler(info); | ||
613 | if (ret < 0) { | ||
614 | dev_err(info->dev, "Cannot detect charger cable\n"); | ||
615 | mutex_unlock(&info->mutex); | ||
616 | return ret; | ||
617 | } | ||
618 | } | ||
469 | 619 | ||
470 | chg_type = status[1] & STATUS2_CHGTYP_MASK; | 620 | mutex_unlock(&info->mutex); |
471 | chg_type >>= STATUS2_CHGTYP_SHIFT; | ||
472 | 621 | ||
473 | max8997_muic_handle_adc(info, adc); | 622 | return 0; |
474 | max8997_muic_handle_charger_type(info, chg_type); | ||
475 | } | 623 | } |
476 | 624 | ||
477 | static int max8997_muic_probe(struct platform_device *pdev) | 625 | static int max8997_muic_probe(struct platform_device *pdev) |
@@ -550,10 +698,16 @@ static int max8997_muic_probe(struct platform_device *pdev) | |||
550 | max8997_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS); | 698 | max8997_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS); |
551 | 699 | ||
552 | /* Initial device detection */ | 700 | /* Initial device detection */ |
553 | max8997_muic_detect_dev(info); | 701 | ret = max8997_muic_detect_dev(info); |
702 | if (ret < 0) { | ||
703 | dev_err(&pdev->dev, "failed to detect cable type\n"); | ||
704 | goto err_extcon; | ||
705 | } | ||
554 | 706 | ||
555 | return ret; | 707 | return ret; |
556 | 708 | ||
709 | err_extcon: | ||
710 | extcon_dev_unregister(info->edev); | ||
557 | err_irq: | 711 | err_irq: |
558 | while (--i >= 0) | 712 | while (--i >= 0) |
559 | free_irq(muic_irqs[i].virq, info); | 713 | free_irq(muic_irqs[i].virq, info); |