Beispiel #1
0
int smdhsic_pm_resume_AP(void)
{
	int r;
	int expire = 500;
	int pending_spin = 20;
	int suspended_spin = 20;
	struct completion done;
	struct device *dev;

	if (!g_usbdev.usbdev) {
		smdctl_request_connection_recover(true);
		return -ENODEV;
	}

	dev = &g_usbdev.usbdev->dev;

retry:
	/* dpm_suspending can be set during RPM STATUS changing */
	if (g_usbdev.hsic && g_usbdev.hsic->dpm_suspending)
		return -EAGAIN;

	switch (dev->power.runtime_status) {
	case RPM_SUSPENDED:
		pr_debug("%s: HSIC suspended\n", __func__);
		init_completion(&done);
		r = smdctl_request_slave_wakeup(&done);
		if (r <= 0 &&
			!wait_for_completion_timeout(&done,
						msecs_to_jiffies(expire))) {
			pr_err("%s: HSIC Resume timeout %d\n",
			       __func__, expire);
			r = smdctl_request_slave_wakeup(NULL);
			if (r <= 0) {
				if (g_usbdev.hsic &&
					g_usbdev.hsic->resume_failcnt++ > 5) {
					g_usbdev.hsic->resume_failcnt = 0;
					smdctl_request_connection_recover(true);
					return -EFAULT;
				}
				return -ETIMEDOUT;
			}
		}

		if (suspended_spin-- <= 0) {
			if (g_usbdev.hsic &&
				g_usbdev.hsic->resume_failcnt++ > 5) {
				g_usbdev.hsic->resume_failcnt = 0;
				smdctl_request_connection_recover(true);
				smdctl_request_slave_wakeup(NULL);
				return -EFAULT;
			}
			smdctl_request_slave_wakeup(NULL);
			return -ETIMEDOUT;
		}
		smdctl_request_slave_wakeup(NULL);
		msleep(100);
		goto retry;
	case RPM_SUSPENDING:
	case RPM_RESUMING:
		pr_debug("%s: HSIC status : %d spin: %d\n", __func__,
			dev->power.runtime_status,
			pending_spin);
		if (pending_spin == 0) {
			pr_err("%s: Modem runtime pm timeout\n",
			       __func__);
			if (g_usbdev.hsic &&
				g_usbdev.hsic->resume_failcnt++ > 5) {
				g_usbdev.hsic->resume_failcnt = 0;
				smdctl_request_connection_recover(true);
				return -EFAULT;
			}
			return -ETIMEDOUT;
		}
		pending_spin--;
		usleep_range(5000, 10000);
		goto retry;
	case RPM_ACTIVE:
		if (g_usbdev.hsic)
			g_usbdev.hsic->resume_failcnt = 0;
		break;
	default:
		return -EIO;
	}

	return 0;
}
Beispiel #2
0
static void smdhsic_disconnect(struct usb_interface *intf)
{
	int devid;
	struct usb_interface *smd_intf;
	struct str_intf_priv *intfpriv;
	struct usb_device *device = NULL;

	pr_info("%s: Called\n", __func__);

	intfpriv = usb_get_intfdata(intf);
	if (!intfpriv) {
		pr_err("%s: intfpriv is NULL\n", __func__);
		goto err_get_intfdata;
	}
	device = get_usb_device(intfpriv);
	devid = GET_DEVID(intfpriv->devid);
	pr_debug("%s : devid : %d\n", __func__, devid);

	smd_intf = get_usb_intf(intfpriv);
	if (!smd_intf) {
		pr_err("smd_intf is NULL\n");
		goto err_get_usb_intf;
	}

	if (smd_intf != intf) {
		pr_err("smd_intf is not same intf\n");
		goto err_mismatched_intf;
	}

	usb_driver_release_interface(get_usb_driver(intf), smd_intf);

	if (!device)
		usb_put_dev(device);

	pm_runtime_disable(&device->dev);
	if (g_usbdev.hsic)
		cancel_delayed_work(&g_usbdev.hsic->pm_runtime_work);

	switch (devid) {
	case FMT_DEV_ID:
		flush_txurb(&g_usbdev.ipc_urbq);
		flush_txurb(&g_usbdev.data_urbq);
		smdctl_request_connection_recover(true);
	case RAW_DEV_ID:
	case RFS_DEV_ID:
	case CMD_DEV_ID:
	case DOWN_DEV_ID:
		if (emu_discon_func[devid])
			emu_discon_func[devid](g_usbdev.smd_device[devid]);
		else
			kfree(intfpriv->data);
		break;
	default:
		pr_warn("%s:Undefined Callback Function\n",
		       __func__);
	}
	/* to prevent sleep at connection recover
	* when, usb suspend and recover routine overlap
	* it makes huge delay on modem reset
	*/
	wake_lock_timeout(&g_usbdev.txwake, 20*HZ);
	kfree(intfpriv);
	usb_set_intfdata(intf, NULL);
	g_usbdev.usbdev = NULL;
	g_usbdev.suspended = 0;
	g_usbdev.hsic = NULL;
	return;

err_mismatched_intf:
err_get_usb_intf:
	if (!device)
		usb_put_dev(device);
err_get_intfdata:
	pr_err("release(2) : %p\n", intf);
	usb_driver_release_interface(get_usb_driver(intf), intf);
	return;
}
Beispiel #3
0
int smdhsic_pm_resume(void)
{
	int r = 0;
	int spin = 20;
	struct device *dev;

	pr_debug("%s\n", __func__);

	if (!g_usbdev.usbdev) {
		smdctl_request_connection_recover(true);
		return -EFAULT;
	}

	if (g_usbdev.hsic && g_usbdev.hsic->dpm_suspending) {
		pr_debug("%s : dpm is suspending just return\n", __func__);
		return 0;
	}

	dev = &g_usbdev.usbdev->dev;

	if (usb_runtime_pm_ap_initiated_L2) {
wait_active:
		if (g_usbdev.hsic && g_usbdev.hsic->dpm_suspending) {
			pr_debug("%s : dpm is suspending just return\n",
				__func__);
			return 0;
		}
		switch (dev->power.runtime_status) {
		case RPM_SUSPENDED:
			r = pm_runtime_resume(dev);
			if (!r && dev->power.timer_expires == 0
			 		&& dev->power.request_pending == false) {
	                			pr_err("%s:run time idle\n", __func__);
					pm_runtime_idle(dev);
			} else if (r < 0) {
				pr_err("%s : pm_runtime_resume failed : %d\n", __func__, r);
				smdctl_request_connection_recover(true);
				return r;
			}
			msleep(20);
			goto wait_active;
			break;
		case RPM_SUSPENDING:
		case RPM_RESUMING:
			if (spin-- < 0) {
				if (g_usbdev.hsic &&
					g_usbdev.hsic->resume_failcnt++ > 5) {
					g_usbdev.hsic->resume_failcnt = 0;
					smdctl_request_connection_recover(true);
					return -EFAULT;
				}
				return -ETIMEDOUT;
			}
			msleep(20);
			goto wait_active;
		case RPM_ACTIVE:
			if (g_usbdev.hsic)
				g_usbdev.hsic->resume_failcnt = 0;
			break;
		default:
			break;
		}
		return 0;
	}

	pr_debug("%s (%d)\n", __func__, dev->power.runtime_status);

	pr_debug("%s(pwr.usg_cnt:%d)\n",
		__func__, atomic_read(&dev->power.usage_count));
	if (!(atomic_read(&dev->power.usage_count)))
		r = pm_runtime_get_sync(dev);

	pr_debug("%s done %d \t %d\n",
		__func__, r, dev->power.usage_count.counter);
	return r;
}
Beispiel #4
0
static void smdhsic_disconnect(struct usb_interface *intf)
{
	int devid;
	struct usb_interface *smd_intf;
	struct str_intf_priv *intfpriv;
	struct usb_device *device = NULL;

	pr_info("%s: Called\n", __func__);

	intfpriv = usb_get_intfdata(intf);
	if (!intfpriv) {
		pr_err("%s: intfpriv is NULL\n", __func__);
		goto err_get_intfdata;
	}
	device = get_usb_device(intfpriv);
	devid = GET_DEVID(intfpriv->devid);
	pr_debug("%s : devid : %d\n", __func__, devid);

	smd_intf = get_usb_intf(intfpriv);
	if (!smd_intf) {
		pr_err("smd_intf is NULL\n");
		goto err_get_usb_intf;
	}

	if (smd_intf != intf) {
		pr_err("smd_intf is not same intf\n");
		goto err_mismatched_intf;
	}

	usb_driver_release_interface(get_usb_driver(intf), smd_intf);

	if (!device)
		usb_put_dev(device);

	switch (devid) {
	case FMT_DEV_ID:
		pm_runtime_disable(&device->dev);
		if (g_usbdev.hsic)
			cancel_delayed_work(&g_usbdev.hsic->pm_runtime_work);

		smdctl_request_connection_recover(true);
	case RAW_DEV_ID:
	case RFS_DEV_ID:
	case CMD_DEV_ID:
	case DOWN_DEV_ID:
		if (emu_discon_func[devid])
			emu_discon_func[devid](g_usbdev.smd_device[devid]);
		else
			kfree(intfpriv->data);
		break;
	default:
		pr_warn("%s:Undefined Callback Function\n",
		       __func__);
	}

	/* Power on/off kernel-panic workaround,
	 * if USB suspend cmd was queued in power.work before disconnect,
	 * reset the runtime PM request value to PM_REQ_NONE
	 */
	device->dev.power.request = RPM_REQ_NONE;

	kfree(intfpriv);
	usb_set_intfdata(intf, NULL);
	g_usbdev.usbdev = NULL;
	g_usbdev.suspended = 0;
	g_usbdev.hsic = NULL;
	return;

err_mismatched_intf:
err_get_usb_intf:
	if (device)
		usb_put_dev(device);
err_get_intfdata:
	pr_err("release(2) : %p\n", intf);
	usb_driver_release_interface(get_usb_driver(intf), intf);
	return;
}