long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
				unsigned long arg)
{
	int status, ret = 0;

	if (_IOC_TYPE(cmd) != CHARM_CODE) {
		pr_err("%s: invalid ioctl code\n", __func__);
		return -EINVAL;
	}

	pr_debug("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
	switch (cmd) {
	case WAKE_CHARM:
		pr_info("%s: Powering on mdm\n", __func__);
		mdm_drv->ops->power_on_mdm_cb(mdm_drv);
		break;
	case CHECK_FOR_BOOT:
		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
			put_user(1, (unsigned long __user *) arg);
		else
			put_user(0, (unsigned long __user *) arg);
		break;
	case NORMAL_BOOT_DONE:
		pr_debug("%s: check if mdm is booted up\n", __func__);
		get_user(status, (unsigned long __user *) arg);
		if (status) {
			pr_debug("%s: normal boot failed\n", __func__);
			mdm_drv->mdm_boot_status = -EIO;
		} else {
			pr_info("%s: normal boot done\n", __func__);
			mdm_drv->mdm_boot_status = 0;
		}
		mdm_drv->mdm_ready = 1;

		if (mdm_drv->ops->normal_boot_done_cb != NULL)
			mdm_drv->ops->normal_boot_done_cb(mdm_drv);

		if (!first_boot)
			complete(&mdm_boot);
		else
			first_boot = 0;

		/* Start a timer to check that the mdm2ap_status gpio
		 * goes high.
		 */

		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
			schedule_delayed_work(&mdm2ap_status_check_work,
				msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS));
		break;
	case RAM_DUMP_DONE:
		pr_debug("%s: mdm done collecting RAM dumps\n", __func__);
		get_user(status, (unsigned long __user *) arg);
		if (status)
			mdm_drv->mdm_ram_dump_status = -EIO;
		else {
			pr_info("%s: ramdump collection completed\n", __func__);
			mdm_drv->mdm_ram_dump_status = 0;
		}
		complete(&mdm_ram_dumps);
		break;
	case WAIT_FOR_RESTART:
		pr_debug("%s: wait for mdm to need images reloaded\n",
				__func__);
		ret = wait_for_completion_interruptible(&mdm_needs_reload);
		if (!ret)
			put_user(mdm_drv->boot_type,
					 (unsigned long __user *) arg);
		INIT_COMPLETION(mdm_needs_reload);
		break;
	case GET_DLOAD_STATUS:
		pr_debug("getting status of mdm2ap_errfatal_gpio\n");
		if (gpio_get_value(mdm_drv->mdm2ap_errfatal_gpio) == 1 &&
			!mdm_drv->mdm_ready)
			put_user(1, (unsigned long __user *) arg);
		else
			put_user(0, (unsigned long __user *) arg);
		break;
	case SHUTDOWN_CHARM:
		if (!mdm_drv->pdata->send_shdn)
			break;
		mdm_drv->mdm_ready = 0;
		if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
			pr_info("Sending shutdown request to mdm\n");
		ret = sysmon_send_shutdown(SYSMON_SS_EXT_MODEM);
		if (ret)
			pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
				   __func__, ret);
		put_user(ret, (unsigned long __user *) arg);
		break;
	default:
		pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
		ret = -EINVAL;
		break;
	}

	return ret;
}
Ejemplo n.º 2
0
static int mdm_cmd_exe(enum esoc_cmd cmd, struct esoc_clink *esoc)
{
	int ret;
	unsigned long end_time;
	bool status_down = false;
	struct mdm_ctrl *mdm = get_esoc_clink_data(esoc);
	struct device *dev = mdm->dev;

	switch (cmd) {
	case ESOC_PWR_ON:
		gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
		mdm_enable_irqs(mdm);
		mdm->init = 1;
		mdm_do_first_power_on(mdm);
		break;
	case ESOC_PWR_OFF:
		mdm_disable_irqs(mdm);
		mdm->debug = 0;
		mdm->ready = false;
		ret = sysmon_send_shutdown(mdm->sysmon_subsys_id);
		device_lock(dev);
		if (ret)
			dev_err(mdm->dev, "Graceful shutdown fail, ret = %d\n",
									ret);
		else {
			dev_info(mdm->dev, "Waiting for status gpio go low\n");
			status_down = false;
			end_time = jiffies + msecs_to_jiffies(10000);
			while (time_before(jiffies, end_time)) {
				if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS))
									== 0) {
					dev_dbg(dev, "Status went low\n");
					status_down = true;
					break;
				}
				msleep(100);
			}
			if (status_down)
				dev_info(dev, "shutdown successful\n");
			else
				dev_err(mdm->dev, "graceful poff ipc fail\n");
		}
		/*
		 * Force a shutdown of the mdm. This is required in order
		 * to prevent the mdm from immediately powering back on
		 * after the shutdown
		 */
		gpio_set_value(MDM_GPIO(mdm, AP2MDM_STATUS), 0);
		esoc_clink_queue_request(ESOC_REQ_SHUTDOWN, esoc);
		mdm_power_down(mdm);
		mdm_update_gpio_configs(mdm, GPIO_UPDATE_BOOTING_CONFIG);
		device_unlock(dev);
		break;
	case ESOC_RESET:
		mdm_toggle_soft_reset(mdm);
		break;
	case ESOC_PREPARE_DEBUG:
		/*
		 * disable all irqs except request irq (pblrdy)
		 * force a reset of the mdm by signaling
		 * an APQ crash, wait till mdm is ready for ramdumps.
		 */
		mdm->ready = false;
		cancel_delayed_work(&mdm->mdm2ap_status_check_work);
		gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1);
		dev_info(mdm->dev, "set ap2mdm errfatal to force reset\n");
		msleep(mdm->ramdump_delay_ms);
		break;
	case ESOC_EXE_DEBUG:
		mdm->debug = 1;
		mdm_toggle_soft_reset(mdm);
		/*
		 * wait for ramdumps to be collected
		 * then power down the mdm and switch gpios to booting
		 * config
		 */
		if (!wait_for_completion_timeout(&mdm->debug_done,
				msecs_to_jiffies(mdm->dump_timeout_ms))) {
			dev_err(mdm->dev, "ramdump collection timedout\n");
			mdm->debug = 0;
			return -ETIMEDOUT;
		}
		if (mdm->debug_fail) {
			dev_err(mdm->dev, "unable to collect ramdumps\n");
			mdm->debug = 0;
			return -EIO;
		}
		dev_dbg(mdm->dev, "ramdump collection done\n");
		mdm->debug = 0;
		init_completion(&mdm->debug_done);
		break;
	case ESOC_EXIT_DEBUG:
		/*
		 * Deassert APQ to mdm err fatal
		 * Power on the mdm
		 */
		gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0);
		dev_dbg(mdm->dev, "exiting debug state after power on\n");
		mdm->get_restart_reason = true;
	      break;
	default:
	      return -EINVAL;
	};
	return 0;
}
long qsc_modem_ioctl(struct file *filp, unsigned int cmd,
				unsigned long arg)
{
	int status, ret = 0, retry = 0;

	if (_IOC_TYPE(cmd) != CHARM_CODE) {
		pr_err("%s: invalid ioctl code\n", __func__);
		return -EINVAL;
	}

	pr_debug("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
	switch (cmd) {
	case WAKE_CHARM:
		if( qsc_bootup_state == QSC_BOOT_MDM_BOOTLOAER_IRQ_REGISTERED || qsc_bootup_state == QSC_BOOT_MDM_BOOTLOAER_IRQ_RECEIVED )
		{
			do {
				retry++;
				ret = wait_for_completion_interruptible_timeout(&qsc_boot_after_mdm_booloader_irq, msecs_to_jiffies(10000));
			} while ( ret == -ERESTARTSYS && retry <= 3); /* interrupted, need retry */
		}

		if( qsc_bootup_state == QSC_BOOT_MDM_BOOTLOAER_IRQ_RECEIVED || qsc_bootup_state == QSC_BOOT_MDM_BOOTLOAER_IRQ_BOOTED )
		{
			retry = 0;
			while( qsc_bootup_state != QSC_BOOT_MDM_BOOTLOAER_IRQ_BOOTED && retry < QSC_POWON_MDM_HELPER_DELAY_TIMES )
			{
				retry++;
				msleep(QSC_POWON_MDM_HELPER_DELAY_INTERVAL_MS);
			}
			if( qsc_bootup_state == QSC_BOOT_MDM_BOOTLOAER_IRQ_RECEIVED )
			{
				pr_err("%s: QSC boot by mdm bootloader irq took too long time.\n", __func__);
			}
			else
			{
				pr_info("%s: QSC has been booted by mdm bootloader irq.\n", __func__);
			}
		}
		else
		{
			qsc_bootup_state = QSC_BOOT_MDM_HELPER_BOOTING;
			pr_info("%s: Powering on qsc by WAKE_CHARM\n", __func__);
			mdm_drv->ops->power_on_mdm_cb(mdm_drv);
			qsc_bootup_state = QSC_BOOT_MDM_HELPER_BOOTED;
		}
		
		INIT_COMPLETION(qsc_boot_after_mdm_booloader_irq);
		break;
	case CHECK_FOR_BOOT:
		if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
			put_user(1, (unsigned long __user *) arg);
		else
			put_user(0, (unsigned long __user *) arg);
		break;
	case NORMAL_BOOT_DONE:
		pr_debug("%s: check if qsc is booted up\n", __func__);
		get_user(status, (unsigned long __user *) arg);
		if (status) {
			pr_debug("%s: normal boot failed\n", __func__);
			mdm_drv->mdm_boot_status = -EIO;
		} else {
			pr_info("%s: normal boot done\n", __func__);
			mdm_drv->mdm_boot_status = 0;
		}
		mdm_drv->mdm_ready = 1;

		if (mdm_drv->ops->normal_boot_done_cb != NULL)
			mdm_drv->ops->normal_boot_done_cb(mdm_drv);

		if (!first_boot)
			complete(&qsc_boot);
		else
			first_boot = 0;

		/* If successful, start a timer to check that the mdm2ap_status
		 * gpio goes high.
		 */
		if (!status && gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
			schedule_delayed_work(&qsc2ap_status_check_work,
				msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS));
		break;
	case RAM_DUMP_DONE:
		pr_debug("%s: qsc done collecting RAM dumps\n", __func__);
		get_user(status, (unsigned long __user *) arg);
		if (status)
			mdm_drv->mdm_ram_dump_status = -EIO;
		else {
			pr_info("%s: ramdump collection completed\n", __func__);
			mdm_drv->mdm_ram_dump_status = 0;
		}
		complete(&qsc_ram_dumps);
		break;
	case WAIT_FOR_RESTART:
		pr_debug("%s: wait for qsc to need images reloaded\n",
				__func__);
		ret = wait_for_completion_interruptible(&qsc_needs_reload);
		if (!ret)
			put_user(mdm_drv->boot_type,
					 (unsigned long __user *) arg);
		INIT_COMPLETION(qsc_needs_reload);
		break;
	case FORCE_DLOAD:
		pr_info("%s: Force QSC enter DLOAD.\n", __func__);
		if( gpio_get_value(mdm_drv->mdm2ap_vddmin_gpio) )
		{
			pr_info("%s: HW Reset case, QSC already in Dload mode.\n", __func__);
			print_qsc_gpio();
		}
		else
		{
			gpio_direction_output(mdm_drv->ap2mdm_vddmin_gpio, 1);
			print_qsc_gpio();
			mdm_drv->ops->atomic_reset_mdm_cb(mdm_drv);
			mdelay(10);
		}
		break;
	case GET_DLOAD_STATUS:
		pr_debug("getting status of qsc2ap_errfatal_gpio\n");
		if (gpio_get_value(mdm_drv->mdm2ap_errfatal_gpio) == 1 &&
			!mdm_drv->mdm_ready)
			put_user(1, (unsigned long __user *) arg);
		else
			put_user(0, (unsigned long __user *) arg);
		break;
	case IMAGE_UPGRADE:
		pr_debug("%s Image upgrade ioctl recieved\n", __func__);
		if (mdm_drv->pdata->image_upgrade_supported &&
				mdm_drv->ops->image_upgrade_cb) {
			get_user(status, (unsigned long __user *) arg);
			mdm_drv->ops->image_upgrade_cb(mdm_drv, status);
		} else
			pr_debug("%s Image upgrade not supported\n", __func__);
		break;
	case SHUTDOWN_CHARM:
		if (!mdm_drv->pdata->send_shdn)
			break;
		mdm_drv->mdm_ready = 0;
		if (qsc_debug_mask & MDM_DEBUG_MASK_SHDN_LOG)
			pr_info("Sending shutdown request to mdm\n");
		ret = sysmon_send_shutdown(SYSMON_SS_EXT_MODEM);
		if (ret)
			pr_err("%s: Graceful shutdown of the external modem failed, ret = %d\n",
				   __func__, ret);
		break;
	default:
		pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
		ret = -EINVAL;
		break;
	}

	return ret;
}