aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2012-12-02 23:09:41 -0500
committerChanwoo Choi <cw00.choi@samsung.com>2013-01-15 01:42:15 -0500
commit39bf369e4ed321158eb8dc5031b4a9f2108ea614 (patch)
treec9a06d4e8d0c94b1b9274b3d8760c1e764816dbb /drivers/extcon
parentd0587eb794da221a5c210348abc8f6cceae93896 (diff)
extcon: max77693: Add support dock device and buttons
This patch support detection of dock device with extcon and buttons of dock device for playing music with input subsystem. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com>
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/extcon-max77693.c255
1 files changed, 216 insertions, 39 deletions
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 26ce4dfeda10..07ea96bfd0cb 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>
@@ -44,11 +45,15 @@ struct max77693_muic_info {
44 int prev_cable_type; 45 int prev_cable_type;
45 int prev_cable_type_gnd; 46 int prev_cable_type_gnd;
46 int prev_chg_type; 47 int prev_chg_type;
48 int prev_button_type;
47 u8 status[2]; 49 u8 status[2];
48 50
49 int irq; 51 int irq;
50 struct work_struct irq_work; 52 struct work_struct irq_work;
51 struct mutex mutex; 53 struct mutex mutex;
54
55 /* Button of dock device */
56 struct input_dev *dock;
52}; 57};
53 58
54enum max77693_muic_cable_group { 59enum max77693_muic_cable_group {
@@ -156,7 +161,10 @@ enum {
156 EXTCON_CABLE_JIG_USB_ON, 161 EXTCON_CABLE_JIG_USB_ON,
157 EXTCON_CABLE_JIG_USB_OFF, 162 EXTCON_CABLE_JIG_USB_OFF,
158 EXTCON_CABLE_JIG_UART_OFF, 163 EXTCON_CABLE_JIG_UART_OFF,
159 EXTCON_CABLE_AUDIO_VIDEO_LOAD, 164 EXTCON_CABLE_JIG_UART_ON,
165 EXTCON_CABLE_DOCK_SMART,
166 EXTCON_CABLE_DOCK_DESK,
167 EXTCON_CABLE_DOCK_AUDIO,
160 168
161 _EXTCON_CABLE_NUM, 169 _EXTCON_CABLE_NUM,
162}; 170};
@@ -173,7 +181,10 @@ const char *max77693_extcon_cable[] = {
173 [EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON", 181 [EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON",
174 [EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF", 182 [EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
175 [EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF", 183 [EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
176 [EXTCON_CABLE_AUDIO_VIDEO_LOAD] = "Audio-video-load", 184 [EXTCON_CABLE_JIG_UART_ON] = "Dock-Car",
185 [EXTCON_CABLE_DOCK_SMART] = "Dock-Smart",
186 [EXTCON_CABLE_DOCK_DESK] = "Dock-Desk",
187 [EXTCON_CABLE_DOCK_AUDIO] = "Dock-Audio",
177 188
178 NULL, 189 NULL,
179}; 190};
@@ -411,6 +422,96 @@ static int max77693_muic_get_cable_type(struct max77693_muic_info *info,
411 return cable_type; 422 return cable_type;
412} 423}
413 424
425static int max77693_muic_dock_handler(struct max77693_muic_info *info,
426 int cable_type, bool attached)
427{
428 int ret = 0;
429 char dock_name[CABLE_NAME_MAX];
430
431 dev_info(info->dev,
432 "external connector is %s (adc:0x%02x)\n",
433 attached ? "attached" : "detached", cable_type);
434
435 switch (cable_type) {
436 case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
437 /* PATH:AP_USB */
438 ret = max77693_muic_set_path(info,
439 CONTROL1_SW_USB, attached);
440 if (ret < 0)
441 goto out;
442
443 /* Dock-Smart */
444 extcon_set_cable_state(info->edev, "Dock-Smart", attached);
445 goto out;
446 case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* Dock-Car */
447 strcpy(dock_name, "Dock-Car");
448 break;
449 case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */
450 strcpy(dock_name, "Dock-Desk");
451 break;
452 case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
453 strcpy(dock_name, "Dock-Audio");
454 if (!attached)
455 extcon_set_cable_state(info->edev, "USB", false);
456 break;
457 }
458
459 /* Dock-Car/Desk/Audio, PATH:AUDIO */
460 ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
461 if (ret < 0)
462 goto out;
463 extcon_set_cable_state(info->edev, dock_name, attached);
464
465out:
466 return ret;
467}
468
469static int max77693_muic_dock_button_handler(struct max77693_muic_info *info,
470 int button_type, bool attached)
471{
472 struct input_dev *dock = info->dock;
473 unsigned int code;
474 int ret = 0;
475
476 switch (button_type) {
477 case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON-1
478 ... MAX77693_MUIC_ADC_REMOTE_S3_BUTTON+1:
479 /* DOCK_KEY_PREV */
480 code = KEY_PREVIOUSSONG;
481 break;
482 case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON-1
483 ... MAX77693_MUIC_ADC_REMOTE_S7_BUTTON+1:
484 /* DOCK_KEY_NEXT */
485 code = KEY_NEXTSONG;
486 break;
487 case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON:
488 /* DOCK_VOL_DOWN */
489 code = KEY_VOLUMEDOWN;
490 break;
491 case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON:
492 /* DOCK_VOL_UP */
493 code = KEY_VOLUMEUP;
494 break;
495 case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON-1
496 ... MAX77693_MUIC_ADC_REMOTE_S12_BUTTON+1:
497 /* DOCK_KEY_PLAY_PAUSE */
498 code = KEY_PLAYPAUSE;
499 break;
500 default:
501 dev_err(info->dev,
502 "failed to detect %s key (adc:0x%x)\n",
503 attached ? "pressed" : "released", button_type);
504 ret = -EINVAL;
505 goto out;
506 }
507
508 input_event(dock, EV_KEY, code, attached);
509 input_sync(dock);
510
511out:
512 return 0;
513}
514
414static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) 515static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
415{ 516{
416 int cable_type_gnd; 517 int cable_type_gnd;
@@ -494,6 +595,7 @@ out:
494static int max77693_muic_adc_handler(struct max77693_muic_info *info) 595static int max77693_muic_adc_handler(struct max77693_muic_info *info)
495{ 596{
496 int cable_type; 597 int cable_type;
598 int button_type;
497 bool attached; 599 bool attached;
498 int ret = 0; 600 int ret = 0;
499 601
@@ -519,31 +621,58 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info)
519 if (ret < 0) 621 if (ret < 0)
520 goto out; 622 goto out;
521 break; 623 break;
522 case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: 624 case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
523 case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: 625 case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* Dock-Car */
524 /* Audio Video cable with no-load */ 626 case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */
525 ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); 627 case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
628 /*
629 * DOCK device
630 *
631 * The MAX77693 MUIC device can detect total 34 cable type
632 * except of charger cable and MUIC device didn't define
633 * specfic role of cable in the range of from 0x01 to 0x12
634 * of ADC value. So, can use/define cable with no role according
635 * to schema of hardware board.
636 */
637 ret = max77693_muic_dock_handler(info, cable_type, attached);
638 if (ret < 0)
639 goto out;
640 break;
641 case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON: /* DOCK_KEY_PREV */
642 case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON: /* DOCK_KEY_NEXT */
643 case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON: /* DOCK_VOL_DOWN */
644 case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON: /* DOCK_VOL_UP */
645 case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON: /* DOCK_KEY_PLAY_PAUSE */
646 /*
647 * Button of DOCK device
648 * - the Prev/Next/Volume Up/Volume Down/Play-Pause button
649 *
650 * The MAX77693 MUIC device can detect total 34 cable type
651 * except of charger cable and MUIC device didn't define
652 * specfic role of cable in the range of from 0x01 to 0x12
653 * of ADC value. So, can use/define cable with no role according
654 * to schema of hardware board.
655 */
656 if (attached)
657 button_type = info->prev_button_type = cable_type;
658 else
659 button_type = info->prev_button_type;
660
661 ret = max77693_muic_dock_button_handler(info, button_type,
662 attached);
526 if (ret < 0) 663 if (ret < 0)
527 goto out; 664 goto out;
528 extcon_set_cable_state(info->edev,
529 "Audio-video-noload", attached);
530 break; 665 break;
531 case MAX77693_MUIC_ADC_SEND_END_BUTTON: 666 case MAX77693_MUIC_ADC_SEND_END_BUTTON:
532 case MAX77693_MUIC_ADC_REMOTE_S1_BUTTON: 667 case MAX77693_MUIC_ADC_REMOTE_S1_BUTTON:
533 case MAX77693_MUIC_ADC_REMOTE_S2_BUTTON: 668 case MAX77693_MUIC_ADC_REMOTE_S2_BUTTON:
534 case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON:
535 case MAX77693_MUIC_ADC_REMOTE_S4_BUTTON: 669 case MAX77693_MUIC_ADC_REMOTE_S4_BUTTON:
536 case MAX77693_MUIC_ADC_REMOTE_S5_BUTTON: 670 case MAX77693_MUIC_ADC_REMOTE_S5_BUTTON:
537 case MAX77693_MUIC_ADC_REMOTE_S6_BUTTON: 671 case MAX77693_MUIC_ADC_REMOTE_S6_BUTTON:
538 case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON:
539 case MAX77693_MUIC_ADC_REMOTE_S8_BUTTON: 672 case MAX77693_MUIC_ADC_REMOTE_S8_BUTTON:
540 case MAX77693_MUIC_ADC_REMOTE_S9_BUTTON:
541 case MAX77693_MUIC_ADC_REMOTE_S10_BUTTON:
542 case MAX77693_MUIC_ADC_REMOTE_S11_BUTTON: 673 case MAX77693_MUIC_ADC_REMOTE_S11_BUTTON:
543 case MAX77693_MUIC_ADC_REMOTE_S12_BUTTON:
544 case MAX77693_MUIC_ADC_RESERVED_ACC_1: 674 case MAX77693_MUIC_ADC_RESERVED_ACC_1:
545 case MAX77693_MUIC_ADC_RESERVED_ACC_2: 675 case MAX77693_MUIC_ADC_RESERVED_ACC_2:
546 case MAX77693_MUIC_ADC_RESERVED_ACC_3:
547 case MAX77693_MUIC_ADC_RESERVED_ACC_4: 676 case MAX77693_MUIC_ADC_RESERVED_ACC_4:
548 case MAX77693_MUIC_ADC_RESERVED_ACC_5: 677 case MAX77693_MUIC_ADC_RESERVED_ACC_5:
549 case MAX77693_MUIC_ADC_CEA936_AUDIO: 678 case MAX77693_MUIC_ADC_CEA936_AUDIO:
@@ -551,11 +680,12 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info)
551 case MAX77693_MUIC_ADC_TTY_CONVERTER: 680 case MAX77693_MUIC_ADC_TTY_CONVERTER:
552 case MAX77693_MUIC_ADC_UART_CABLE: 681 case MAX77693_MUIC_ADC_UART_CABLE:
553 case MAX77693_MUIC_ADC_CEA936A_TYPE1_CHG: 682 case MAX77693_MUIC_ADC_CEA936A_TYPE1_CHG:
554 case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD:
555 case MAX77693_MUIC_ADC_CEA936A_TYPE2_CHG: 683 case MAX77693_MUIC_ADC_CEA936A_TYPE2_CHG:
556 /* This accessory isn't used in general case if it is specially 684 /*
557 needed to detect additional accessory, should implement 685 * This accessory isn't used in general case if it is specially
558 proper operation when this accessory is attached/detached. */ 686 * needed to detect additional accessory, should implement
687 * proper operation when this accessory is attached/detached.
688 */
559 dev_info(info->dev, 689 dev_info(info->dev,
560 "accessory is %s but it isn't used (adc:0x%x)\n", 690 "accessory is %s but it isn't used (adc:0x%x)\n",
561 attached ? "attached" : "detached", cable_type); 691 attached ? "attached" : "detached", cable_type);
@@ -576,6 +706,7 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
576{ 706{
577 int chg_type; 707 int chg_type;
578 int cable_type_gnd; 708 int cable_type_gnd;
709 int cable_type;
579 bool attached; 710 bool attached;
580 bool cable_attached; 711 bool cable_attached;
581 int ret = 0; 712 int ret = 0;
@@ -590,35 +721,52 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
590 721
591 switch (chg_type) { 722 switch (chg_type) {
592 case MAX77693_CHARGER_TYPE_USB: 723 case MAX77693_CHARGER_TYPE_USB:
724 /*
725 * MHL_TA(USB/TA) with MHL cable
726 * - MHL cable include two port(HDMI line and separate micro
727 * -usb port. When the target connect MHL cable, extcon driver
728 * check whether MHL_TA(USB/TA) cable is connected. If MHL_TA
729 * cable is connected, extcon driver notify state to notifiee
730 * for charging battery.
731 */
593 cable_type_gnd = max77693_muic_get_cable_type(info, 732 cable_type_gnd = max77693_muic_get_cable_type(info,
594 MAX77693_CABLE_GROUP_ADC_GND, 733 MAX77693_CABLE_GROUP_ADC_GND,
595 &cable_attached); 734 &cable_attached);
596 735 if (cable_type_gnd == MAX77693_MUIC_GND_MHL
597 switch (cable_type_gnd) { 736 || cable_type_gnd == MAX77693_MUIC_GND_MHL_VB) {
598 case MAX77693_MUIC_GND_MHL:
599 case MAX77693_MUIC_GND_MHL_VB:
600 /*
601 * USB/TA with MHL cable
602 * - MHL cable, which connect micro USB or TA cable,
603 * is used to charging battery. So, extcon driver check
604 * charging type whether micro USB or TA cable is
605 * connected to MHL cable when extcon driver detect MHL
606 * cable.
607 */
608 extcon_set_cable_state(info->edev, "MHL_TA", attached); 737 extcon_set_cable_state(info->edev, "MHL_TA", attached);
609 738
610 if (!cable_attached) 739 if (!cable_attached)
611 extcon_set_cable_state(info->edev, 740 extcon_set_cable_state(info->edev,
612 "MHL", false); 741 "MHL", false);
613 break; 742 goto out;
614 default: 743 }
615 /* Only USB cable, PATH:AP_USB */ 744
616 ret = max77693_muic_set_path(info, CONTROL1_SW_USB, 745 /*
617 attached); 746 * USB/TA cable with Dock-Audio device
618 if (ret < 0) 747 * - Dock device include two port(Dock-Audio and micro-usb
619 goto out; 748 * port). When the target connect Dock-Audio device, extcon
749 * driver check whether USB/TA cable is connected.
750 * If USB/TA cable is connected, extcon driver notify state
751 * to notifiee for charging battery.
752 */
753 cable_type = max77693_muic_get_cable_type(info,
754 MAX77693_CABLE_GROUP_ADC,
755 &cable_attached);
756 if (cable_type == MAX77693_MUIC_ADC_AV_CABLE_NOLOAD) {
620 extcon_set_cable_state(info->edev, "USB", attached); 757 extcon_set_cable_state(info->edev, "USB", attached);
758
759 if (!cable_attached)
760 extcon_set_cable_state(info->edev,
761 "Dock-Audio", false);
762 goto out;
621 } 763 }
764
765 /* Only USB cable, PATH:AP_USB */
766 ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached);
767 if (ret < 0)
768 goto out;
769 extcon_set_cable_state(info->edev, "USB", attached);
622 break; 770 break;
623 case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT: 771 case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT:
624 extcon_set_cable_state(info->edev, 772 extcon_set_cable_state(info->edev,
@@ -794,6 +942,32 @@ static int max77693_muic_probe(struct platform_device *pdev)
794 return ret; 942 return ret;
795 } 943 }
796 } 944 }
945
946 /* Register input device for button of dock device */
947 info->dock = input_allocate_device();
948 if (!info->dock) {
949 dev_err(&pdev->dev, "%s: failed to allocate input\n", __func__);
950 return -ENOMEM;
951 }
952 info->dock->name = "max77693-muic/dock";
953 info->dock->phys = "max77693-muic/extcon";
954 info->dock->dev.parent = &pdev->dev;
955
956 __set_bit(EV_REP, info->dock->evbit);
957
958 input_set_capability(info->dock, EV_KEY, KEY_VOLUMEUP);
959 input_set_capability(info->dock, EV_KEY, KEY_VOLUMEDOWN);
960 input_set_capability(info->dock, EV_KEY, KEY_PLAYPAUSE);
961 input_set_capability(info->dock, EV_KEY, KEY_PREVIOUSSONG);
962 input_set_capability(info->dock, EV_KEY, KEY_NEXTSONG);
963
964 ret = input_register_device(info->dock);
965 if (ret < 0) {
966 dev_err(&pdev->dev, "Cannot register input device error(%d)\n",
967 ret);
968 return ret;
969 }
970
797 platform_set_drvdata(pdev, info); 971 platform_set_drvdata(pdev, info);
798 mutex_init(&info->mutex); 972 mutex_init(&info->mutex);
799 973
@@ -870,7 +1044,7 @@ static int max77693_muic_probe(struct platform_device *pdev)
870 MAX77693_MUIC_REG_ID, &id); 1044 MAX77693_MUIC_REG_ID, &id);
871 if (ret < 0) { 1045 if (ret < 0) {
872 dev_err(&pdev->dev, "failed to read revision number\n"); 1046 dev_err(&pdev->dev, "failed to read revision number\n");
873 goto err_irq; 1047 goto err_extcon;
874 } 1048 }
875 dev_info(info->dev, "device ID : 0x%x\n", id); 1049 dev_info(info->dev, "device ID : 0x%x\n", id);
876 1050
@@ -882,6 +1056,8 @@ static int max77693_muic_probe(struct platform_device *pdev)
882 1056
883 return ret; 1057 return ret;
884 1058
1059err_extcon:
1060 extcon_dev_unregister(info->edev);
885err_irq: 1061err_irq:
886 while (--i >= 0) 1062 while (--i >= 0)
887 free_irq(muic_irqs[i].virq, info); 1063 free_irq(muic_irqs[i].virq, info);
@@ -896,6 +1072,7 @@ static int max77693_muic_remove(struct platform_device *pdev)
896 for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) 1072 for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
897 free_irq(muic_irqs[i].virq, info); 1073 free_irq(muic_irqs[i].virq, info);
898 cancel_work_sync(&info->irq_work); 1074 cancel_work_sync(&info->irq_work);
1075 input_unregister_device(info->dock);
899 extcon_dev_unregister(info->edev); 1076 extcon_dev_unregister(info->edev);
900 1077
901 return 0; 1078 return 0;