static int max8997_muic_handle_usb(struct max8997_muic_info *info, enum max8997_muic_usb_type usb_type, bool attached) { int ret = 0; if (usb_type == MAX8997_USB_HOST) { ret = max8997_muic_set_path(info, info->path_usb, attached); if (ret < 0) { dev_err(info->dev, "failed to update muic register\n"); return ret; } } switch (usb_type) { case MAX8997_USB_HOST: extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached); break; case MAX8997_USB_DEVICE: extcon_set_cable_state_(info->edev, EXTCON_USB, attached); break; default: dev_err(info->dev, "failed to detect %s usb cable\n", attached ? "attached" : "detached"); return -EINVAL; } return 0; }
static irqreturn_t max3355_id_irq(int irq, void *dev_id) { struct max3355_data *data = dev_id; int id = gpiod_get_value_cansleep(data->id_gpiod); if (id) { /* * ID = 1 means USB HOST cable detached. * As we don't have event for USB peripheral cable attached, * we simulate USB peripheral attach here. */ extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, false); extcon_set_cable_state_(data->edev, EXTCON_USB, true); } else { /* * ID = 0 means USB HOST cable attached. * As we don't have event for USB peripheral cable detached, * we simulate USB peripheral detach here. */ extcon_set_cable_state_(data->edev, EXTCON_USB, false); extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, true); } return IRQ_HANDLED; }
static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb) { struct palmas_usb *palmas_usb = _palmas_usb; struct extcon_dev *edev = palmas_usb->edev; unsigned int vbus_line_state; palmas_read(palmas_usb->palmas, PALMAS_INTERRUPT_BASE, PALMAS_INT3_LINE_STATE, &vbus_line_state); if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) { if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) { palmas_usb->linkstat = PALMAS_USB_STATE_VBUS; extcon_set_cable_state_(edev, EXTCON_USB, true); dev_info(palmas_usb->dev, "USB cable is attached\n"); } else { dev_dbg(palmas_usb->dev, "Spurious connect event detected\n"); } } else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) { if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) { palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; extcon_set_cable_state_(edev, EXTCON_USB, false); dev_info(palmas_usb->dev, "USB cable is detached\n"); } else { dev_dbg(palmas_usb->dev, "Spurious disconnect event detected\n"); } } return IRQ_HANDLED; }
static void rcar_gen3_init_for_peri(struct rcar_gen3_chan *ch) { rcar_gen3_set_linectrl(ch, 0, 1); rcar_gen3_set_host_mode(ch, 0); rcar_gen3_enable_vbus_ctrl(ch, 0); extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false); extcon_set_cable_state_(ch->extcon, EXTCON_USB, true); }
static int max14577_muic_chg_handler(struct max14577_muic_info *info) { int chg_type; bool attached; int ret = 0; chg_type = max14577_muic_get_cable_type(info, MAX14577_CABLE_GROUP_CHG, &attached); dev_dbg(info->dev, "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n", attached ? "attached" : "detached", chg_type, info->prev_chg_type); switch (chg_type) { case MAX14577_CHARGER_TYPE_USB: /* PATH:AP_USB */ ret = max14577_muic_set_path(info, info->path_usb, attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_USB, attached); break; case MAX14577_CHARGER_TYPE_DEDICATED_CHG: extcon_set_cable_state_(info->edev, EXTCON_TA, attached); break; case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT: extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM, attached); break; case MAX14577_CHARGER_TYPE_SPECIAL_500MA: extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER, attached); break; case MAX14577_CHARGER_TYPE_SPECIAL_1A: extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER, attached); break; case MAX14577_CHARGER_TYPE_NONE: case MAX14577_CHARGER_TYPE_DEAD_BATTERY: break; default: dev_err(info->dev, "failed to detect %s accessory (chg_type:0x%x)\n", attached ? "attached" : "detached", chg_type); return -EINVAL; } return 0; }
static int max77693_muic_jig_handler(struct max77693_muic_info *info, int cable_type, bool attached) { int ret = 0; u8 path = MAX77693_CONTROL1_SW_OPEN; dev_info(info->dev, "external connector is %s (adc:0x%02x)\n", attached ? "attached" : "detached", cable_type); switch (cable_type) { case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */ case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */ /* PATH:AP_USB */ path = MAX77693_CONTROL1_SW_USB; break; case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */ case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* ADC_JIG_UART_ON */ /* PATH:AP_UART */ path = MAX77693_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) return ret; extcon_set_cable_state_(info->edev, EXTCON_JIG, attached); return 0; }
static int max8997_muic_chg_handler(struct max8997_muic_info *info) { int chg_type; bool attached; int adc; chg_type = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_CHG, &attached); switch (chg_type) { case MAX8997_CHARGER_TYPE_NONE: break; case MAX8997_CHARGER_TYPE_USB: adc = info->status[0] & STATUS1_ADC_MASK; adc >>= STATUS1_ADC_SHIFT; if ((adc & STATUS1_ADC_MASK) == MAX8997_MUIC_ADC_OPEN) { max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, attached); } break; case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM, attached); break; case MAX8997_CHARGER_TYPE_DEDICATED_CHG: extcon_set_cable_state_(info->edev, EXTCON_TA, attached); break; case MAX8997_CHARGER_TYPE_500MA: extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER, attached); break; case MAX8997_CHARGER_TYPE_1A: extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER, attached); break; default: dev_err(info->dev, "failed to detect %s unknown chg cable (type:0x%x)\n", attached ? "attached" : "detached", chg_type); return -EINVAL; } return 0; }
static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) { int cable_type_gnd; int ret = 0; bool attached; cable_type_gnd = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC_GND, &attached); switch (cable_type_gnd) { case MAX77693_MUIC_GND_USB_HOST: case MAX77693_MUIC_GND_USB_HOST_VB: /* USB_HOST, PATH: AP_USB */ ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_USB, attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached); break; case MAX77693_MUIC_GND_AV_CABLE_LOAD: /* Audio Video Cable with load, PATH:AUDIO */ ret = max77693_muic_set_path(info, MAX77693_CONTROL1_SW_AUDIO, attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_USB, attached); extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SDP, attached); break; case MAX77693_MUIC_GND_MHL: case MAX77693_MUIC_GND_MHL_VB: /* MHL or MHL with USB/TA cable */ extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, attached); break; default: dev_err(info->dev, "failed to detect %s cable of gnd type\n", attached ? "attached" : "detached"); return -EINVAL; } return 0; }
static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) { unsigned int set, id_src; struct palmas_usb *palmas_usb = _palmas_usb; struct extcon_dev *edev = palmas_usb->edev; palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_ID_INT_LATCH_SET, &set); palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_ID_INT_SRC, &id_src); if ((set & PALMAS_USB_ID_INT_SRC_ID_GND) && (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) { palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_ID_INT_LATCH_CLR, PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND); palmas_usb->linkstat = PALMAS_USB_STATE_ID; extcon_set_cable_state_(edev, EXTCON_USB_HOST, true); dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); } else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) && (id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) { palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_ID_INT_LATCH_CLR, PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT); palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; extcon_set_cable_state_(edev, EXTCON_USB_HOST, false); dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) && (!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) { palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; extcon_set_cable_state_(edev, EXTCON_USB_HOST, false); dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) && (id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) { palmas_usb->linkstat = PALMAS_USB_STATE_ID; extcon_set_cable_state_(edev, EXTCON_USB_HOST, true); dev_info(palmas_usb->dev, " USB-HOST cable is attached\n"); } return IRQ_HANDLED; }
static void palmas_gpio_id_detect(struct work_struct *work) { int id; struct palmas_usb *palmas_usb = container_of(to_delayed_work(work), struct palmas_usb, wq_detectid); struct extcon_dev *edev = palmas_usb->edev; if (!palmas_usb->id_gpiod) return; id = gpiod_get_value_cansleep(palmas_usb->id_gpiod); if (id) { extcon_set_cable_state_(edev, EXTCON_USB_HOST, false); dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); } else { extcon_set_cable_state_(edev, EXTCON_USB_HOST, true); dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); } }
static irqreturn_t arizona_jackdet(int irq, void *data) { struct arizona_extcon_info *info = data; struct arizona *arizona = info->arizona; unsigned int val; int ret; pm_runtime_get_sync(info->dev); mutex_lock(&info->lock); ret = regmap_read(arizona->regmap, ARIZONA_AOD_IRQ_RAW_STATUS, &val); if (ret != 0) { dev_err(arizona->dev, "Failed to read jackdet status: %d\n", ret); mutex_unlock(&info->lock); pm_runtime_put_autosuspend(info->dev); return IRQ_NONE; } if (val & ARIZONA_JD1_STS) { dev_dbg(arizona->dev, "Detected jack\n"); ret = extcon_set_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL, true); if (ret != 0) dev_err(arizona->dev, "Mechanical report failed: %d\n", ret); arizona_start_mic(info); } else { dev_dbg(arizona->dev, "Detected jack removal\n"); arizona_stop_mic(info); ret = extcon_update_state(&info->edev, 0xffffffff, 0); if (ret != 0) dev_err(arizona->dev, "Removal report failed: %d\n", ret); } mutex_unlock(&info->lock); pm_runtime_mark_last_busy(info->dev); pm_runtime_put_autosuspend(info->dev); return IRQ_HANDLED; }
static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, bool attached) { int ret = 0; /* switch to UART */ ret = max8997_muic_set_path(info, info->path_uart, attached); if (ret) { dev_err(info->dev, "failed to update muic register\n"); return ret; } extcon_set_cable_state_(info->edev, EXTCON_JIG, attached); return 0; }
static int max8997_muic_handle_dock(struct max8997_muic_info *info, int cable_type, bool attached) { int ret = 0; ret = max8997_muic_set_path(info, CONTROL1_SW_AUDIO, attached); if (ret) { dev_err(info->dev, "failed to update muic register\n"); return ret; } switch (cable_type) { case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD: case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON: extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached); break; default: dev_err(info->dev, "failed to detect %s dock device\n", attached ? "attached" : "detached"); return -EINVAL; } return 0; }
static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info) { static bool notify_otg, notify_charger; static unsigned int cable; int ret, stat, cfg, pwr_stat; u8 chrg_type; bool vbus_attach = false; ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat); if (ret < 0) { dev_err(info->dev, "failed to read vbus status\n"); return ret; } vbus_attach = (pwr_stat & PS_STAT_VBUS_PRESENT); if (!vbus_attach) goto notify_otg; /* Check charger detection completion status */ ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg); if (ret < 0) goto dev_det_ret; if (cfg & BC_GLOBAL_DET_STAT) { dev_dbg(info->dev, "can't complete the charger detection\n"); goto dev_det_ret; } ret = regmap_read(info->regmap, AXP288_BC_DET_STAT_REG, &stat); if (ret < 0) goto dev_det_ret; chrg_type = (stat & DET_STAT_MASK) >> DET_STAT_SHIFT; switch (chrg_type) { case DET_STAT_SDP: dev_dbg(info->dev, "sdp cable is connecetd\n"); notify_otg = true; notify_charger = true; cable = EXTCON_CHG_USB_SDP; break; case DET_STAT_CDP: dev_dbg(info->dev, "cdp cable is connecetd\n"); notify_otg = true; notify_charger = true; cable = EXTCON_CHG_USB_CDP; break; case DET_STAT_DCP: dev_dbg(info->dev, "dcp cable is connecetd\n"); notify_charger = true; cable = EXTCON_CHG_USB_DCP; break; default: dev_warn(info->dev, "disconnect or unknown or ID event\n"); } notify_otg: if (notify_otg) { /* * If VBUS is absent Connect D+/D- lines to PMIC for BC * detection. Else connect them to SOC for USB communication. */ if (info->pdata->gpio_mux_cntl) gpiod_set_value(info->pdata->gpio_mux_cntl, vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC : EXTCON_GPIO_MUX_SEL_PMIC); atomic_notifier_call_chain(&info->otg->notifier, vbus_attach ? USB_EVENT_VBUS : USB_EVENT_NONE, NULL); } if (notify_charger) extcon_set_cable_state_(info->edev, cable, vbus_attach); /* Clear the flags on disconnect event */ if (!vbus_attach) notify_otg = notify_charger = false; return 0; dev_det_ret: if (ret < 0) dev_err(info->dev, "failed to detect BC Mod\n"); return ret; }
static int max77693_muic_chg_handler(struct max77693_muic_info *info) { int chg_type; int cable_type_gnd; int cable_type; bool attached; bool cable_attached; int ret = 0; chg_type = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_CHG, &attached); dev_info(info->dev, "external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n", attached ? "attached" : "detached", chg_type, info->prev_chg_type); switch (chg_type) { case MAX77693_CHARGER_TYPE_USB: 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); switch (cable_type_gnd) { case MAX77693_MUIC_GND_MHL: case MAX77693_MUIC_GND_MHL_VB: /* * MHL cable with 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 USB/TA cable is * connected. If USB/TA cable is connected, extcon * driver notify state to notifiee for charging battery. * * Features of 'USB/TA with MHL cable' * - Support MHL * - Support charging through micro-usb port without * data connection */ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP, attached); if (!cable_attached) extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, cable_attached); break; } /* Check MAX77693_CABLE_GROUP_ADC type */ cable_type = max77693_muic_get_cable_type(info, MAX77693_CABLE_GROUP_ADC, &cable_attached); 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 * or not. 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, EXTCON_USB, attached); if (!cable_attached) extcon_set_cable_state_(info->edev, EXTCON_DOCK, 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(On-The-Go) device (Ex: Mouse/Keyboard) */ ret = max77693_muic_set_path(info, info->path_usb, attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached); extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, attached); break; } /* 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 irq. * - '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 * irq than MAX77693_MUIC_IRQ_INT2_CHGTYP irq. * * If user attach MHL (with USB/TA cable and immediately * detach MHL with USB/TA cable before MAX77693_MUIC_IRQ * _INT2_CHGTYP irq 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, EXTCON_USB, attached); break; case MAX77693_CHARGER_TYPE_DEDICATED_CHG: /* Only TA cable */ extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_DCP, attached); break; } break; case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT: extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_CDP, attached); break; case MAX77693_CHARGER_TYPE_APPLE_500MA: extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_SLOW, attached); break; case MAX77693_CHARGER_TYPE_APPLE_1A_2A: extcon_set_cable_state_(info->edev, EXTCON_CHG_USB_FAST, attached); break; case MAX77693_CHARGER_TYPE_DEAD_BATTERY: break; default: dev_err(info->dev, "failed to detect %s accessory (chg_type:0x%x)\n", attached ? "attached" : "detached", chg_type); return -EINVAL; } return 0; }
static int max77693_muic_dock_handler(struct max77693_muic_info *info, int cable_type, bool attached) { int ret = 0; int vbvolt; bool cable_attached; unsigned int dock_id; dev_info(info->dev, "external connector is %s (adc:0x%02x)\n", attached ? "attached" : "detached", cable_type); switch (cable_type) { case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ /* * 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/MHL state. * - Dock device include three type of cable which * are HDMI, USB for mouse/keyboard and micro-usb port * for USB/TA cable. Dock device need always exteranl * power supply(USB/TA cable through micro-usb cable). Dock * device support screen output of target to separate * monitor and mouse/keyboard for desktop mode. * * Features of 'USB/TA cable with Dock 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(On-The-Go) device (Ex: Mouse/Keyboard) */ ret = max77693_muic_set_path(info, info->path_usb, attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached); extcon_set_cable_state_(info->edev, EXTCON_DISP_MHL, attached); goto out; case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */ dock_id = EXTCON_DOCK; break; case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */ dock_id = EXTCON_DOCK; if (!attached) extcon_set_cable_state_(info->edev, EXTCON_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, MAX77693_CONTROL1_SW_AUDIO, attached); if (ret < 0) return ret; extcon_set_cable_state_(info->edev, dock_id, attached); out: return 0; }
static irqreturn_t arizona_micdet(int irq, void *data) { struct arizona_extcon_info *info = data; struct arizona *arizona = info->arizona; unsigned int val; int ret; mutex_lock(&info->lock); ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); if (ret != 0) { dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); return IRQ_NONE; } dev_dbg(arizona->dev, "MICDET: %x\n", val); if (!(val & ARIZONA_MICD_VALID)) { dev_warn(arizona->dev, "Microphone detection state invalid\n"); mutex_unlock(&info->lock); return IRQ_NONE; } /* Due to jack detect this should never happen */ if (!(val & ARIZONA_MICD_STS)) { dev_warn(arizona->dev, "Detected open circuit\n"); info->detecting = false; goto handled; } /* If we got a high impedence we should have a headset, report it. */ if (info->detecting && (val & 0x400)) { ret = extcon_update_state(&info->edev, 1 << ARIZONA_CABLE_MICROPHONE | 1 << ARIZONA_CABLE_HEADPHONE, 1 << ARIZONA_CABLE_MICROPHONE | 1 << ARIZONA_CABLE_HEADPHONE); if (ret != 0) dev_err(arizona->dev, "Headset report failed: %d\n", ret); info->mic = true; info->detecting = false; goto handled; } /* If we detected a lower impedence during initial startup * then we probably have the wrong polarity, flip it. Don't * do this for the lowest impedences to speed up detection of * plain headphones. If both polarities report a low * impedence then give up and report headphones. */ if (info->detecting && (val & 0x3f8)) { info->jack_flips++; if (info->jack_flips >= info->micd_num_modes) { dev_dbg(arizona->dev, "Detected headphone\n"); info->detecting = false; arizona_stop_mic(info); ret = extcon_set_cable_state_(&info->edev, ARIZONA_CABLE_HEADPHONE, true); if (ret != 0) dev_err(arizona->dev, "Headphone report failed: %d\n", ret); } else { info->micd_mode++; if (info->micd_mode == info->micd_num_modes) info->micd_mode = 0; arizona_extcon_set_mode(info, info->micd_mode); info->jack_flips++; } goto handled; } /* * If we're still detecting and we detect a short then we've * got a headphone. Otherwise it's a button press, the * button reporting is stubbed out for now. */ if (val & 0x3fc) { if (info->mic) { dev_dbg(arizona->dev, "Mic button detected\n"); } else if (info->detecting) { dev_dbg(arizona->dev, "Headphone detected\n"); info->detecting = false; arizona_stop_mic(info); ret = extcon_set_cable_state_(&info->edev, ARIZONA_CABLE_HEADPHONE, true); if (ret != 0) dev_err(arizona->dev, "Headphone report failed: %d\n", ret); } else { dev_warn(arizona->dev, "Button with no mic: %x\n", val); } } else { dev_dbg(arizona->dev, "Mic button released\n"); } handled: pm_runtime_mark_last_busy(info->dev); mutex_unlock(&info->lock); return IRQ_HANDLED; }
static int max8997_muic_adc_handler(struct max8997_muic_info *info) { int cable_type; bool attached; int ret = 0; /* Check cable state which is either detached or attached */ cable_type = max8997_muic_get_cable_type(info, MAX8997_CABLE_GROUP_ADC, &attached); switch (cable_type) { case MAX8997_MUIC_ADC_GROUND: ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, attached); if (ret < 0) return ret; break; case MAX8997_MUIC_ADC_MHL: extcon_set_cable_state_(info->edev, EXTCON_MHL, attached); break; case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF: case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON: ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, attached); if (ret < 0) return ret; break; case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD: case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON: ret = max8997_muic_handle_dock(info, cable_type, attached); if (ret < 0) return ret; break; case MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF: ret = max8997_muic_handle_jig_uart(info, attached); break; case MAX8997_MUIC_ADC_REMOTE_S1_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S2_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S3_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S4_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S5_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S6_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S7_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S8_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S9_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S10_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S11_BUTTON: case MAX8997_MUIC_ADC_REMOTE_S12_BUTTON: case MAX8997_MUIC_ADC_RESERVED_ACC_1: case MAX8997_MUIC_ADC_RESERVED_ACC_2: case MAX8997_MUIC_ADC_RESERVED_ACC_3: case MAX8997_MUIC_ADC_RESERVED_ACC_4: case MAX8997_MUIC_ADC_RESERVED_ACC_5: case MAX8997_MUIC_ADC_CEA936_AUDIO: case MAX8997_MUIC_ADC_PHONE_POWERED_DEV: case MAX8997_MUIC_ADC_TTY_CONVERTER: case MAX8997_MUIC_ADC_UART_CABLE: case MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG: case MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG: case MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE: /* * This cable isn't used in general case if it is specially * needed to detect additional cable, should implement * proper operation when this cable is attached/detached. */ dev_info(info->dev, "cable is %s but it isn't used (type:0x%x)\n", attached ? "attached" : "detached", cable_type); return -EAGAIN; default: dev_err(info->dev, "failed to detect %s unknown cable (type:0x%x)\n", attached ? "attached" : "detached", cable_type); return -EINVAL; } return 0; }