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 irqreturn_t smsc375x_irq_handler(int irq, void *data) { struct smsc375x_chip *chip = data; pm_runtime_get_sync(&chip->client->dev); dev_info(&chip->client->dev, "SMSC USB INT!\n"); smsc375x_detect_dev(chip); pm_runtime_put_sync(&chip->client->dev); return IRQ_HANDLED; }
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_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct smsc375x_chip *chip; int ret = 0, id_val = -1; chip = kzalloc(sizeof(struct smsc375x_chip), GFP_KERNEL); if (!chip) { dev_err(&client->dev, "failed to allocate driver data\n"); return -ENOMEM; } chip->client = client; #ifdef CONFIG_ACPI chip->pdata = smsc375x_platform_data(); #else chip->pdata = dev->platform_data; #endif i2c_set_clientdata(client, chip); wake_lock_init(&chip->wakelock, WAKE_LOCK_SUSPEND, "smsc375x_wakelock"); /* register with extcon */ chip->edev = kzalloc(sizeof(struct extcon_dev), GFP_KERNEL); if (!chip->edev) { dev_err(&client->dev, "mem alloc failed\n"); ret = -ENOMEM; goto extcon_mem_failed; } chip->edev->name = "smsc375x"; chip->edev->supported_cable = smsc375x_extcon_cable; ret = extcon_dev_register(chip->edev, &client->dev); if (ret) { dev_err(&client->dev, "extcon registration failed!!\n"); goto extcon_reg_failed; } /* register for EXTCON USB notification */ INIT_WORK(&chip->vbus_work, smsc375x_pwrsrc_event_worker); chip->vbus_nb.notifier_call = smsc375x_handle_pwrsrc_notification; ret = extcon_register_interest(&chip->cable_obj, NULL, SMSC375X_EXTCON_USB, &chip->vbus_nb); /* OTG notification */ chip->otg = usb_get_phy(USB_PHY_TYPE_USB2); if (!chip->otg) { dev_warn(&client->dev, "Failed to get otg transceiver!!\n"); goto otg_reg_failed; } INIT_WORK(&chip->otg_work, smsc375x_otg_event_worker); chip->id_nb.notifier_call = smsc375x_handle_otg_notification; ret = usb_register_notifier(chip->otg, &chip->id_nb); if (ret) { dev_err(&chip->client->dev, "failed to register otg notifier\n"); goto id_reg_failed; } ret = smsc375x_irq_init(chip); if (ret) goto intr_reg_failed; chip_ptr = chip; if (chip->otg->get_id_status) { ret = chip->otg->get_id_status(chip->otg, &id_val); if (ret < 0) { dev_warn(&client->dev, "otg get ID status failed:%d\n", ret); ret = 0; } } if (!id_val && !chip->id_short) atomic_notifier_call_chain(&chip->otg->notifier, USB_EVENT_ID, &id_val); else smsc375x_detect_dev(chip); /* Init Runtime PM State */ pm_runtime_put_noidle(&chip->client->dev); pm_schedule_suspend(&chip->client->dev, MSEC_PER_SEC); return 0; intr_reg_failed: usb_unregister_notifier(chip->otg, &chip->id_nb); id_reg_failed: usb_put_phy(chip->otg); otg_reg_failed: extcon_dev_unregister(chip->edev); extcon_reg_failed: kfree(chip->edev); extcon_mem_failed: kfree(chip); return ret; }