static int modem_powerup(const struct subsys_desc *subsys)
{
	struct modem_data *drv = subsys_to_drv(subsys);

	if (subsys->is_not_loadable)
		return 0;
	/*
	 * At this time, the modem is shutdown. Therefore this function cannot
	 * run concurrently with the watchdog bite error handler, making it safe
	 * to unset the flag below.
	 */
	INIT_COMPLETION(drv->stop_ack);
	drv->subsys_desc.ramdump_disable = 0;
	drv->ignore_errors = false;
	drv->q6->desc.fw_name = subsys->fw_name;
	return pil_boot(&drv->q6->desc);
}
static int modem_ramdump(int enable, const struct subsys_desc *subsys)
{
	struct modem_data *drv = subsys_to_drv(subsys);
	int ret;

	if (!enable)
		return 0;

	ret = pil_boot(&drv->q6->desc);
	if (ret)
		return ret;

	ret = pil_do_ramdump(&drv->mba->desc, drv->ramdump_dev);
	if (ret < 0)
		pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);

	pil_shutdown(&drv->q6->desc);
	return ret;
}
static int riva_powerup(const struct subsys_desc *desc)
{
	struct riva_data *drv;
	struct platform_device *pdev = wcnss_get_platform_device();
	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
	int ret = 0;

	drv = container_of(desc, struct riva_data, subsys_desc);
	if (pdev && pwlanconfig) {
		ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
					WCNSS_WLAN_SWITCH_ON, NULL);
		if (!ret)
			pil_boot(&drv->pil_desc);
	}
	drv->rst_in_progress = 0;
	enable_irq(drv->irq);
	schedule_delayed_work(&drv->cancel_work, msecs_to_jiffies(5000));

	return ret;
}
static int wcnss_powerup(const struct subsys_desc *subsys)
{
	struct pronto_data *drv = subsys_to_drv(subsys);
	struct platform_device *pdev = wcnss_get_platform_device();
	struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
	int    ret = -1;

	if (pdev && pwlanconfig)
		ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
					WCNSS_WLAN_SWITCH_ON, NULL);
	if (!ret) {
		msleep(1000);
		ret = pil_boot(&drv->desc);
		if (ret)
			return ret;
	}
	drv->restart_inprogress = false;
	enable_irq(drv->irq);
	schedule_delayed_work(&drv->cancel_vote_work, msecs_to_jiffies(5000));

	return 0;
}
static int tzapps_start(const struct subsys_desc *desc)
{
	struct tzapps_data *drv = subsys_to_drv(desc);

	return pil_boot(&drv->pil_desc);
}
static int vidc_powerup(const struct subsys_desc *desc)
{
	struct vidc_data *drv = subsys_to_drv(desc);
	return pil_boot(&drv->pil_desc);
}
static void modem_crash_shutdown(const struct subsys_desc *subsys)
{
	struct modem_data *drv = subsys_to_drv(subsys);
	drv->crash_shutdown = true;
#ifdef CONFIG_LGE_HANDLE_PANIC
	if (!subsys_get_crash_status(drv->subsys) && (lge_get_modem_panic() != 3)) {
#else
	if (!subsys_get_crash_status(drv->subsys)) {
#endif
		gpio_set_value(subsys->force_stop_gpio, 1);
		mdelay(STOP_ACK_TIMEOUT_MS);
	}
}

static int modem_ramdump(int enable, const struct subsys_desc *subsys)
{
	struct modem_data *drv = subsys_to_drv(subsys);
	int ret;

	if (!enable)
		return 0;

	ret = pil_boot(&drv->q6->desc);
	if (ret)
		return ret;

	ret = pil_do_ramdump(&drv->mba->desc, drv->ramdump_dev);
	if (ret < 0)
		pr_err("Unable to dump modem fw memory (rc = %d).\n", ret);

	pil_shutdown(&drv->q6->desc);
	return ret;
}

static int adsp_state_notifier_fn(struct notifier_block *this,
				unsigned long code, void *ss_handle)
{
	int ret;
	ret = sysmon_send_event(SYSMON_SS_MODEM, "adsp", code);
	if (ret < 0)
		pr_err("%s: sysmon_send_event failed (%d).", __func__, ret);
	return NOTIFY_DONE;
}

static struct notifier_block adsp_state_notifier_block = {
	.notifier_call = adsp_state_notifier_fn,
};

static irqreturn_t modem_wdog_bite_intr_handler(int irq, void *dev_id)
{
	struct modem_data *drv = subsys_to_drv(dev_id);
	if (drv->ignore_errors)
		return IRQ_HANDLED;

	/* START : subsys_modem_restart : testmode */
	if (ignore_errors_by_subsys_modem_restart) {
		pr_err("IGNORE watchdog bite received from modem software!\n");
		return IRQ_HANDLED;
	}
	/* END : subsys_modem_restart : testmode */

	if (check_modem_reset(drv) == 0) {
		pr_err("IGNORE watchdog bite received from modem software during check_modem_reset!\n");
		return IRQ_HANDLED;
	}

	pr_err("Watchdog bite received from modem software!\n");
#if defined(CONFIG_PRE_SELF_DIAGNOSIS)
	lge_pre_self_diagnosis((char *) "modem", 2, (char *) "Watchdog bite Intr", (char *) "_", 20000);
#endif

	subsys_set_crash_status(drv->subsys, true);
	restart_modem(drv);
	return IRQ_HANDLED;
}

static int mss_start(const struct subsys_desc *desc)
{
	int ret;
	struct modem_data *drv = subsys_to_drv(desc);

	if (desc->is_not_loadable)
		return 0;

	INIT_COMPLETION(drv->stop_ack);
	ret = pil_boot(&drv->q6->desc);
	if (ret)
		return ret;
	ret = pil_boot(&drv->mba->desc);
	if (ret)
		pil_shutdown(&drv->q6->desc);
	return ret;
}
static int dsps_start(const struct subsys_desc *desc)
{
	struct dsps_data *drv = desc_to_drv(desc);

	return pil_boot(&drv->desc);
}
static int pronto_start(const struct subsys_desc *desc)
{
	struct pronto_data *drv = subsys_to_drv(desc);
	return pil_boot(&drv->desc);
}
static int bcss_powerup(const struct subsys_desc *subsys)
{
	struct bcss_data *drv = subsys_to_drv(subsys);

	return pil_boot(&drv->desc);
}
static int pil_femto_modem_start(struct femto_modem_data *drv)
{
	int ret;
	u32 index;

	/* MBA must load, else we can't load any firmware images */
	SET_SYSFS_VALUE(drv, mba_status, MODEM_STATUS_MBA_LOADING);
	ret = pil_boot(&drv->q6->desc);
	if (ret) {
		SET_SYSFS_VALUE(drv, mba_status, MODEM_STATUS_MBA_ERROR);
		return ret;
	}
	SET_SYSFS_VALUE(drv, mba_status, MODEM_STATUS_MBA_RUNNING);

	/* Load the other modem images, if possible. */
	for (index = 0; index < drv->max_num_modems; index++) {
		struct modem_pil_data *modem = &drv->modem[index];
		int img;
		char *pmi_name = kzalloc((strlen(modem->name) + 5), GFP_KERNEL);
		struct modem_data *image = &modem->image;

		if (!pmi_name) {
			ret = -ENOMEM;
			SET_SYSFS_VALUE(modem, status, MODEM_STATUS_PMI_ERROR);
			pil_shutdown(&drv->q6->desc);
			break;
		}

		/* Initialize stats */
		SET_SYSFS_VALUE(modem, imgs_loaded, 0);
		SET_SYSFS_VALUE(modem, last_img_loaded, -1);
		SET_SYSFS_VALUE(modem, img_loading, -1);

		/* Try to load each image. */
		for (img = 0; img < modem->num_images; img++) {
			SET_SYSFS_VALUE(modem, status,
				MODEM_STATUS_PMI_LOADING);
			SET_SYSFS_VALUE(modem, img_loading, img);

			/* The filename for each image is name_nn, where nn is
			 * the 2 digit image index.
			 */
			pmi_name[0] = '\0';
			snprintf(pmi_name, (strlen(modem->name) + 5), "%s_%02u",
				 modem->name, img);

			/* Have to change the descriptor name so it boots the
			 * correct file.
			 */
			image->desc.name = pmi_name;

			/* Try to boot the image. */
			ret = pil_boot(&image->desc);
			if (ret) {
				SET_SYSFS_VALUE(modem, status,
					MODEM_STATUS_PMI_NOT_FOUND);
				if (!modem->id) {
					/* This is a catastrophic failure.
					 * Modem 0 must load.
					 */
					pil_shutdown(&drv->q6->desc);
					break;
				} else
					/* This image didn't load, but it's not
					 * a catastrophic failure; continue
					 * loading.
					 */
					ret = 0;
			} else {
				/* Update stats */
				SET_SYSFS_VALUE(modem, last_img_loaded, img);
				SET_SYSFS_VALUE(modem, img_loading, -1);
				SET_SYSFS_VALUE(modem, imgs_loaded,
					modem->imgs_loaded + 1);
				SET_SYSFS_VALUE(modem, status,
					MODEM_STATUS_PMI_LOADED);
			}
		}

		if (modem->imgs_loaded == 0)
			SET_SYSFS_VALUE(modem, status, MODEM_STATUS_PMI_ERROR);

		/* Free the allocated name */
		kfree(pmi_name);

		if (index == (drv->max_num_modems - 1))
			/* Tell the MBA this was the last RMB */
			ret = pil_femto_modem_send_rmb_advance(
				image->rmb_base,
				RMB_ADVANCE_COMPLETE);
		else {
			/* Tell the MBA to move to the next RMB.
			 * Note that the MBA needs the actual id of the
			 * modem specified in the device tree,
			 * not the logical index.
			 */
			ret = pil_femto_modem_send_rmb_advance(
				image->rmb_base,
				drv->modem[(index + 1)].id);

			if (ret) {
				/* This is a catastrophic failure; we've
				 * gotten out of sync with the MBA.
				 */
				SET_SYSFS_VALUE(modem, status,
					MODEM_STATUS_ADVANCE_FAILED);
				pil_shutdown(&drv->q6->desc);
				break;
			}
		}
	}

	return ret;
}