static int arche_platform_pm_notifier(struct notifier_block *notifier, unsigned long pm_event, void *unused) { struct arche_platform_drvdata *arche_pdata = container_of(notifier, struct arche_platform_drvdata, pm_notifier); int ret = NOTIFY_DONE; mutex_lock(&arche_pdata->platform_state_mutex); switch (pm_event) { case PM_SUSPEND_PREPARE: if (arche_pdata->state != ARCHE_PLATFORM_STATE_ACTIVE) { ret = NOTIFY_STOP; break; } device_for_each_child(arche_pdata->dev, NULL, apb_poweroff); arche_platform_poweroff_seq(arche_pdata); break; case PM_POST_SUSPEND: if (arche_pdata->state != ARCHE_PLATFORM_STATE_OFF) break; arche_platform_wd_irq_en(arche_pdata); arche_platform_coldboot_seq(arche_pdata); break; default: break; } mutex_unlock(&arche_pdata->platform_state_mutex); return ret; }
static void arche_platform_shutdown(struct platform_device *pdev) { struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev); arche_platform_poweroff_seq(arche_pdata); usb3613_hub_mode_ctrl(false); }
static int arche_platform_remove(struct platform_device *pdev) { struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev); unregister_pm_notifier(&arche_pdata->pm_notifier); device_remove_file(&pdev->dev, &dev_attr_state); device_for_each_child(&pdev->dev, NULL, arche_remove_child); arche_platform_poweroff_seq(arche_pdata); if (usb3613_hub_mode_ctrl(false)) dev_warn(arche_pdata->dev, "failed to control hub device\n"); /* TODO: Should we do anything more here ?? */ return 0; }
static ssize_t state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct arche_platform_drvdata *arche_pdata = platform_get_drvdata(pdev); int ret = 0; retry: mutex_lock(&arche_pdata->platform_state_mutex); if (arche_pdata->state == ARCHE_PLATFORM_STATE_TIME_SYNC) { mutex_unlock(&arche_pdata->platform_state_mutex); ret = wait_event_interruptible( arche_pdata->wq, arche_pdata->state != ARCHE_PLATFORM_STATE_TIME_SYNC); if (ret) return ret; goto retry; } if (sysfs_streq(buf, "off")) { if (arche_pdata->state == ARCHE_PLATFORM_STATE_OFF) goto exit; /* If SVC goes down, bring down APB's as well */ device_for_each_child(arche_pdata->dev, NULL, apb_poweroff); arche_platform_poweroff_seq(arche_pdata); } else if (sysfs_streq(buf, "active")) { if (arche_pdata->state == ARCHE_PLATFORM_STATE_ACTIVE) goto exit; /* First we want to make sure we power off everything * and then activate back again */ device_for_each_child(arche_pdata->dev, NULL, apb_poweroff); arche_platform_poweroff_seq(arche_pdata); arche_platform_wd_irq_en(arche_pdata); ret = arche_platform_coldboot_seq(arche_pdata); if (ret) goto exit; } else if (sysfs_streq(buf, "standby")) { if (arche_pdata->state == ARCHE_PLATFORM_STATE_STANDBY) goto exit; dev_warn(arche_pdata->dev, "standby state not supported\n"); } else if (sysfs_streq(buf, "fw_flashing")) { if (arche_pdata->state == ARCHE_PLATFORM_STATE_FW_FLASHING) goto exit; /* * Here we only control SVC. * * In case of FW_FLASHING mode we do not want to control * APBs, as in case of V2, SPI bus is shared between both * the APBs. So let user chose which APB he wants to flash. */ arche_platform_poweroff_seq(arche_pdata); ret = arche_platform_fw_flashing_seq(arche_pdata); if (ret) goto exit; } else { dev_err(arche_pdata->dev, "unknown state\n"); ret = -EINVAL; } exit: mutex_unlock(&arche_pdata->platform_state_mutex); return ret ? ret : count; }