static void smsc375x_pwrsrc_event_worker(struct work_struct *work) { struct smsc375x_chip *chip = container_of(work, struct smsc375x_chip, vbus_work); int ret; pm_runtime_get_sync(&chip->client->dev); if (chip->id_short && chip->pdata->is_vbus_online()) { /* * only after reading the status register * MUX path is being closed. And by default * MUX is to connected Host mode path. */ ret = smsc375x_read_reg(chip->client, SMSC375X_REG_STAT); if (ret < 0) dev_warn(&chip->client->dev, "status read failed%d\n", ret); else dev_info(&chip->client->dev, "Stat:%x\n", ret); } else { smsc375x_detect_dev(chip); } pm_runtime_put_sync(&chip->client->dev); }
static void smsc375x_pwrsrc_event_worker(struct work_struct *work) { struct smsc375x_chip *chip = container_of(work, struct smsc375x_chip, vbus_work); int ret; pm_runtime_get_sync(&chip->client->dev); /* * Sometimes SMSC INT triggering is only * happening after reading the status bits. * So we are reading the status register as WA * to invoke teh MUX INT in case of connect events. */ if (!chip->pdata->is_vbus_online()) ret = smsc375x_detect_dev(chip); else ret = smsc375x_read_reg(chip->client, SMSC375X_REG_STAT); if (ret < 0) dev_warn(&chip->client->dev, "pwrsrc evt error\n"); pm_runtime_put_sync(&chip->client->dev); }
static int smsc375x_detect_dev(struct smsc375x_chip *chip) { struct i2c_client *client = chip->client; static bool notify_otg, notify_charger; static char *cable; static struct power_supply_cable_props cable_props; int stat, cfg, ret, vbus_mask = 0; u8 chrg_type; bool vbus_attach = false; dev_info(&chip->client->dev, "%s\n", __func__); /* * get VBUS status from external IC like * PMIC or Charger as SMSC375x chip can not * be accessed with out VBUS. */ ret = chip->pdata->is_vbus_online(); if (ret < 0) { dev_info(&chip->client->dev, "get vbus stat error\n"); return ret; } if (ret) { dev_info(&chip->client->dev, "VBUS present\n"); vbus_attach = true; } else { dev_info(&chip->client->dev, "VBUS NOT present\n"); vbus_attach = false; cable_props.ma = 0; cable_props.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_DISCONNECT; goto notify_otg_em; } /* dont proceed with charger detection in host mode */ if (chip->id_short) { /* * only after reading the status register * MUX path is being closed. And by default * MUX is to connected Host mode path. */ ret = smsc375x_read_reg(client, SMSC375X_REG_STAT); return ret; } /* check charger detection completion status */ ret = smsc375x_read_reg(client, SMSC375X_REG_STAT); if (ret < 0) goto dev_det_i2c_failed; else stat = ret; if (!(stat & STAT_CHRG_DET_DONE)) { dev_info(&chip->client->dev, "DET failed"); return -EFAULT; } ret = smsc375x_read_reg(client, SMSC375X_REG_CFG); if (ret < 0) goto dev_det_i2c_failed; else cfg = ret; dev_info(&client->dev, "Stat:%x, Cfg:%x\n", stat, cfg); chrg_type = stat & STAT_CHRG_TYPE_MASK; chip->is_sdp = false; if (chrg_type == STAT_CHRG_TYPE_SDP) { dev_info(&chip->client->dev, "SDP cable connecetd\n"); notify_otg = true; vbus_mask = 1; notify_charger = true; chip->is_sdp = true; cable = SMSC375X_EXTCON_SDP; cable_props.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_CONNECT; cable_props.chrg_type = POWER_SUPPLY_CHARGER_TYPE_USB_SDP; if (chip->pdata->charging_compliance_override) cable_props.ma = SMSC_CHARGE_CUR_SDP_500; else cable_props.ma = SMSC_CHARGE_CUR_SDP_100; } else if (chrg_type == STAT_CHRG_TYPE_CDP) { dev_info(&chip->client->dev, "CDP cable connecetd\n"); notify_otg = true; vbus_mask = 1; notify_charger = true; cable = SMSC375X_EXTCON_CDP; cable_props.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_CONNECT; cable_props.chrg_type = POWER_SUPPLY_CHARGER_TYPE_USB_CDP; cable_props.ma = SMSC_CHARGE_CUR_CDP; } else if ((chrg_type == STAT_CHRG_TYPE_DCP) || (chrg_type == STAT_CHRG_TYPE_SE1L) || (chrg_type == STAT_CHRG_TYPE_SE1H)) { dev_info(&chip->client->dev, "DCP/SE1 cable connecetd\n"); notify_charger = true; cable = SMSC375X_EXTCON_DCP; cable_props.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_CONNECT; cable_props.chrg_type = POWER_SUPPLY_CHARGER_TYPE_USB_DCP; cable_props.ma = SMSC_CHARGE_CUR_DCP; if (!wake_lock_active(&chip->wakelock)) wake_lock(&chip->wakelock); } else { dev_warn(&chip->client->dev, "disconnect or unknown or ID event\n"); cable_props.ma = 0; cable_props.chrg_evt = POWER_SUPPLY_CHARGER_EVENT_DISCONNECT; } notify_otg_em: if (!vbus_attach) { /* disconnevt event */ if (notify_otg) { atomic_notifier_call_chain(&chip->otg->notifier, USB_EVENT_VBUS, &vbus_mask); notify_otg = false; } if (notify_charger) { /* * not supporting extcon events currently. * extcon_set_cable_state(chip->edev, cable, false); */ atomic_notifier_call_chain(&power_supply_notifier, POWER_SUPPLY_CABLE_EVENT, &cable_props); notify_charger = false; cable = NULL; } if (wake_lock_active(&chip->wakelock)) wake_unlock(&chip->wakelock); } else { if (notify_otg) { /* close mux path to enable device mode */ ret = smsc375x_write_reg(client, SMSC375X_REG_CFG, (cfg & ~CFG_EN_MUX1) | CFG_EN_MUX2); if (ret < 0) goto dev_det_i2c_failed; atomic_notifier_call_chain(&chip->otg->notifier, USB_EVENT_VBUS, &vbus_mask); } if (notify_charger) { /* * not supporting extcon events currently. * extcon_set_cable_state(chip->edev, cable, true); */ atomic_notifier_call_chain(&power_supply_notifier, POWER_SUPPLY_CABLE_EVENT, &cable_props); } } return 0; dev_det_i2c_failed: if (chip->pdata->is_vbus_online()) dev_err(&chip->client->dev, "vbus present: i2c read failed:%d\n", ret); else dev_info(&chip->client->dev, "vbus removed: i2c read failed:%d\n", ret); return ret; }