X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=drivers%2Fextcon%2Fextcon-max77693.c;h=b70e3815c45932a3b76f7f30fff98d69907a8483;hb=3c834b6f41fa21a48389b13c3bf63aa8df1d7080;hp=abab068adc358eb820c357f632be4dec96895954;hpb=2b75799f5ae9f31ea9778003591fd295d3bc3159;p=~andy%2Flinux diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index abab068adc3..b70e3815c45 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -185,7 +185,7 @@ enum { _EXTCON_CABLE_NUM, }; -const char *max77693_extcon_cable[] = { +static const char *max77693_extcon_cable[] = { [EXTCON_CABLE_USB] = "USB", [EXTCON_CABLE_USB_HOST] = "USB-Host", [EXTCON_CABLE_TA] = "TA", @@ -224,16 +224,17 @@ static int max77693_muic_set_debounce_time(struct max77693_muic_info *info, MAX77693_MUIC_REG_CTRL3, time << CONTROL3_ADCDBSET_SHIFT, CONTROL3_ADCDBSET_MASK); - if (ret) + if (ret) { dev_err(info->dev, "failed to set ADC debounce time\n"); + return -EAGAIN; + } break; default: dev_err(info->dev, "invalid ADC debounce time\n"); - ret = -EINVAL; - break; + return -EINVAL; } - return ret; + return 0; }; /* @@ -261,7 +262,7 @@ static int max77693_muic_set_path(struct max77693_muic_info *info, MAX77693_MUIC_REG_CTRL1, ctrl1, COMP_SW_MASK); if (ret < 0) { dev_err(info->dev, "failed to update MUIC register\n"); - goto out; + return -EAGAIN; } if (attached) @@ -274,14 +275,14 @@ static int max77693_muic_set_path(struct max77693_muic_info *info, CONTROL2_LOWPWR_MASK | CONTROL2_CPEN_MASK); if (ret < 0) { dev_err(info->dev, "failed to update MUIC register\n"); - goto out; + return -EAGAIN; } dev_info(info->dev, "CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n", ctrl1, ctrl2, attached ? "attached" : "detached"); -out: - return ret; + + return 0; } /* @@ -442,6 +443,8 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, int cable_type, bool attached) { int ret = 0; + int vbvolt; + bool cable_attached; char dock_name[CABLE_NAME_MAX]; dev_info(info->dev, @@ -450,14 +453,45 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, switch (cable_type) { case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ - /* PATH:AP_USB */ - ret = max77693_muic_set_path(info, - CONTROL1_SW_USB, attached); + /* + * Check power cable whether attached or detached state. + * The Dock-Smart device need surely external power supply. + * If power cable(USB/TA) isn't connected to Dock device, + * user can't use Dock-Smart for desktop mode. + */ + vbvolt = max77693_muic_get_cable_type(info, + MAX77693_CABLE_GROUP_VBVOLT, &cable_attached); + if (attached && !vbvolt) { + dev_warn(info->dev, + "Cannot detect external power supply\n"); + return 0; + } + + /* + * Notify Dock-Smart/MHL state. + * - Dock-Smart device include three type of cable which + * are HDMI, USB for mouse/keyboard and micro-usb port + * for USB/TA cable. Dock-Smart device need always exteranl + * power supply(USB/TA cable through micro-usb cable). Dock- + * Smart device support screen output of target to separate + * monitor and mouse/keyboard for desktop mode. + * + * Features of 'USB/TA cable with Dock-Smart device' + * - Support MHL + * - Support external output feature of audio + * - Support charging through micro-usb port without data + * connection if TA cable is connected to target. + * - Support charging and data connection through micro-usb port + * if USB cable is connected between target and host + * device. + * - Support OTG device (Mouse/Keyboard) + */ + ret = max77693_muic_set_path(info, info->path_usb, attached); if (ret < 0) - goto out; + return ret; - /* Dock-Smart */ extcon_set_cable_state(info->edev, "Dock-Smart", attached); + extcon_set_cable_state(info->edev, "MHL", attached); goto out; case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* Dock-Car */ strcpy(dock_name, "Dock-Car"); @@ -470,16 +504,20 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, if (!attached) extcon_set_cable_state(info->edev, "USB", false); break; + default: + dev_err(info->dev, "failed to detect %s dock device\n", + attached ? "attached" : "detached"); + return -EINVAL; } /* Dock-Car/Desk/Audio, PATH:AUDIO */ ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); if (ret < 0) - goto out; + return ret; extcon_set_cable_state(info->edev, dock_name, attached); out: - return ret; + return 0; } static int max77693_muic_dock_button_handler(struct max77693_muic_info *info, @@ -487,7 +525,6 @@ static int max77693_muic_dock_button_handler(struct max77693_muic_info *info, { struct input_dev *dock = info->dock; unsigned int code; - int ret = 0; switch (button_type) { case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON-1 @@ -517,14 +554,12 @@ static int max77693_muic_dock_button_handler(struct max77693_muic_info *info, dev_err(info->dev, "failed to detect %s key (adc:0x%x)\n", attached ? "pressed" : "released", button_type); - ret = -EINVAL; - goto out; + return -EINVAL; } input_event(dock, EV_KEY, code, attached); input_sync(dock); -out: return 0; } @@ -543,14 +578,14 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) /* USB_OTG, PATH: AP_USB */ ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); if (ret < 0) - goto out; + return ret; extcon_set_cable_state(info->edev, "USB-Host", attached); break; case MAX77693_MUIC_GND_AV_CABLE_LOAD: /* Audio Video Cable with load, PATH:AUDIO */ ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); if (ret < 0) - goto out; + return ret; extcon_set_cable_state(info->edev, "Audio-video-load", attached); break; @@ -560,14 +595,12 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) extcon_set_cable_state(info->edev, "MHL", attached); break; default: - dev_err(info->dev, "failed to detect %s accessory\n", + dev_err(info->dev, "failed to detect %s cable of gnd type\n", attached ? "attached" : "detached"); - ret = -EINVAL; - break; + return -EINVAL; } -out: - return ret; + return 0; } static int max77693_muic_jig_handler(struct max77693_muic_info *info, @@ -597,15 +630,19 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info, strcpy(cable_name, "JIG-UART-OFF"); path = CONTROL1_SW_UART; break; + default: + dev_err(info->dev, "failed to detect %s jig cable\n", + attached ? "attached" : "detached"); + return -EINVAL; } ret = max77693_muic_set_path(info, path, attached); if (ret < 0) - goto out; + return ret; extcon_set_cable_state(info->edev, cable_name, attached); -out: - return ret; + + return 0; } static int max77693_muic_adc_handler(struct max77693_muic_info *info) @@ -635,7 +672,7 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info) /* JIG */ ret = max77693_muic_jig_handler(info, cable_type, attached); if (ret < 0) - goto out; + return ret; break; case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* Dock-Car */ @@ -652,7 +689,7 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info) */ ret = max77693_muic_dock_handler(info, cable_type, attached); if (ret < 0) - goto out; + return ret; break; case MAX77693_MUIC_ADC_REMOTE_S3_BUTTON: /* DOCK_KEY_PREV */ case MAX77693_MUIC_ADC_REMOTE_S7_BUTTON: /* DOCK_KEY_NEXT */ @@ -677,7 +714,7 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info) ret = max77693_muic_dock_button_handler(info, button_type, attached); if (ret < 0) - goto out; + return ret; break; case MAX77693_MUIC_ADC_SEND_END_BUTTON: case MAX77693_MUIC_ADC_REMOTE_S1_BUTTON: @@ -705,17 +742,15 @@ static int max77693_muic_adc_handler(struct max77693_muic_info *info) dev_info(info->dev, "accessory is %s but it isn't used (adc:0x%x)\n", attached ? "attached" : "detached", cable_type); - goto out; + return -EAGAIN; default: dev_err(info->dev, "failed to detect %s accessory (adc:0x%x)\n", attached ? "attached" : "detached", cable_type); - ret = -EINVAL; - goto out; + return -EINVAL; } -out: - return ret; + return 0; } static int max77693_muic_chg_handler(struct max77693_muic_info *info) @@ -737,60 +772,125 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) switch (chg_type) { case MAX77693_CHARGER_TYPE_USB: - /* - * MHL_TA(USB/TA) with MHL cable - * - MHL cable include two port(HDMI line and separate micro - * -usb port. When the target connect MHL cable, extcon driver - * check whether MHL_TA(USB/TA) cable is connected. If MHL_TA - * cable is connected, extcon driver notify state to notifiee - * for charging battery. - */ + case MAX77693_CHARGER_TYPE_DEDICATED_CHG: + case MAX77693_CHARGER_TYPE_NONE: + /* Check MAX77693_CABLE_GROUP_ADC_GND type */ cable_type_gnd = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC_GND, &cable_attached); - if (cable_type_gnd == MAX77693_MUIC_GND_MHL - || cable_type_gnd == MAX77693_MUIC_GND_MHL_VB) { + switch (cable_type_gnd) { + case MAX77693_MUIC_GND_MHL: + case MAX77693_MUIC_GND_MHL_VB: + /* + * MHL cable with MHL_TA(USB/TA) cable + * - MHL cable include two port(HDMI line and separate micro- + * usb port. When the target connect MHL cable, extcon driver + * check whether MHL_TA(USB/TA) cable is connected. If MHL_TA + * cable is connected, extcon driver notify state to notifiee + * for charging battery. + * + * Features of 'MHL_TA(USB/TA) with MHL cable' + * - Support MHL + * - Support charging through micro-usb port without data connection + */ extcon_set_cable_state(info->edev, "MHL_TA", attached); - if (!cable_attached) - extcon_set_cable_state(info->edev, - "MHL", false); - goto out; + extcon_set_cable_state(info->edev, "MHL", cable_attached); + break; } - /* - * USB/TA cable with Dock-Audio device - * - Dock device include two port(Dock-Audio and micro-usb - * port). When the target connect Dock-Audio device, extcon - * driver check whether USB/TA cable is connected. - * If USB/TA cable is connected, extcon driver notify state - * to notifiee for charging battery. - */ + /* Check MAX77693_CABLE_GROUP_ADC type */ cable_type = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC, &cable_attached); - if (cable_type == MAX77693_MUIC_ADC_AV_CABLE_NOLOAD) { + switch (cable_type) { + case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */ + /* + * Dock-Audio device with USB/TA cable + * - Dock device include two port(Dock-Audio and micro-usb + * port). When the target connect Dock-Audio device, extcon + * driver check whether USB/TA cable is connected. If USB/TA + * cable is connected, extcon driver notify state to notifiee + * for charging battery. + * + * Features of 'USB/TA cable with Dock-Audio device' + * - Support external output feature of audio. + * - Support charging through micro-usb port without data + * connection. + */ extcon_set_cable_state(info->edev, "USB", attached); if (!cable_attached) - extcon_set_cable_state(info->edev, - "Dock-Audio", false); - goto out; + extcon_set_cable_state(info->edev, "Dock-Audio", cable_attached); + break; + case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ + /* + * Dock-Smart device with USB/TA cable + * - Dock-Desk device include three type of cable which + * are HDMI, USB for mouse/keyboard and micro-usb port + * for USB/TA cable. Dock-Smart device need always exteranl + * power supply(USB/TA cable through micro-usb cable). Dock- + * Smart device support screen output of target to separate + * monitor and mouse/keyboard for desktop mode. + * + * Features of 'USB/TA cable with Dock-Smart device' + * - Support MHL + * - Support external output feature of audio + * - Support charging through micro-usb port without data + * connection if TA cable is connected to target. + * - Support charging and data connection through micro-usb port + * if USB cable is connected between target and host + * device. + * - Support OTG device (Mouse/Keyboard) + */ + ret = max77693_muic_set_path(info, info->path_usb, attached); + if (ret < 0) + return ret; + + extcon_set_cable_state(info->edev, "Dock-Smart", attached); + extcon_set_cable_state(info->edev, "MHL", attached); + + break; } - /* Only USB cable, PATH:AP_USB */ - ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); - if (ret < 0) - goto out; - extcon_set_cable_state(info->edev, "USB", attached); + /* Check MAX77693_CABLE_GROUP_CHG type */ + switch (chg_type) { + case MAX77693_CHARGER_TYPE_NONE: + /* + * When MHL(with USB/TA cable) or Dock-Audio with USB/TA cable + * is attached, muic device happen below two interrupt. + * - 'MAX77693_MUIC_IRQ_INT1_ADC' for detecting MHL/Dock-Audio. + * - 'MAX77693_MUIC_IRQ_INT2_CHGTYP' for detecting USB/TA cable + * connected to MHL or Dock-Audio. + * Always, happen eariler MAX77693_MUIC_IRQ_INT1_ADC interrupt + * than MAX77693_MUIC_IRQ_INT2_CHGTYP interrupt. + * + * If user attach MHL (with USB/TA cable and immediately detach + * MHL with USB/TA cable before MAX77693_MUIC_IRQ_INT2_CHGTYP + * interrupt is happened, USB/TA cable remain connected state to + * target. But USB/TA cable isn't connected to target. The user + * be face with unusual action. So, driver should check this + * situation in spite of, that previous charger type is N/A. + */ + break; + case MAX77693_CHARGER_TYPE_USB: + /* Only USB cable, PATH:AP_USB */ + ret = max77693_muic_set_path(info, info->path_usb, attached); + if (ret < 0) + return ret; + + extcon_set_cable_state(info->edev, "USB", attached); + break; + case MAX77693_CHARGER_TYPE_DEDICATED_CHG: + /* Only TA cable */ + extcon_set_cable_state(info->edev, "TA", attached); + break; + } break; case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT: extcon_set_cable_state(info->edev, "Charge-downstream", attached); break; - case MAX77693_CHARGER_TYPE_DEDICATED_CHG: - extcon_set_cable_state(info->edev, "TA", attached); - break; case MAX77693_CHARGER_TYPE_APPLE_500MA: extcon_set_cable_state(info->edev, "Slow-charger", attached); break; @@ -803,12 +903,10 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) dev_err(info->dev, "failed to detect %s accessory (chg_type:0x%x)\n", attached ? "attached" : "detached", chg_type); - ret = -EINVAL; - goto out; + return -EINVAL; } -out: - return ret; + return 0; } static void max77693_muic_irq_work(struct work_struct *work) @@ -863,7 +961,8 @@ static void max77693_muic_irq_work(struct work_struct *work) default: dev_err(info->dev, "muic interrupt: irq %d occurred\n", irq_type); - break; + mutex_unlock(&info->mutex); + return; } if (ret < 0) @@ -911,21 +1010,27 @@ static int max77693_muic_detect_accessory(struct max77693_muic_info *info) &attached); if (attached && adc != MAX77693_MUIC_ADC_OPEN) { ret = max77693_muic_adc_handler(info); - if (ret < 0) + if (ret < 0) { dev_err(info->dev, "Cannot detect accessory\n"); + mutex_unlock(&info->mutex); + return ret; + } } chg_type = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_CHG, &attached); if (attached && chg_type != MAX77693_CHARGER_TYPE_NONE) { ret = max77693_muic_chg_handler(info); - if (ret < 0) + if (ret < 0) { dev_err(info->dev, "Cannot detect charger accessory\n"); + mutex_unlock(&info->mutex); + return ret; + } } mutex_unlock(&info->mutex); - return ret; + return 0; } static void max77693_muic_detect_cable_wq(struct work_struct *work) @@ -970,7 +1075,7 @@ static int max77693_muic_probe(struct platform_device *pdev) } /* Register input device for button of dock device */ - info->dock = input_allocate_device(); + info->dock = devm_input_allocate_device(&pdev->dev); if (!info->dock) { dev_err(&pdev->dev, "%s: failed to allocate input\n", __func__); return -ENOMEM;