Esempio n. 1
0
/**
* hsi_clocks_disable_channel - virtual wrapper for disabling HSI clocks for
* a given channel
* @dev - reference to the hsi device.
* @channel_number - channel number which requests clock to be disabled
*		    0xFF means no particular channel
*
* Note : there is no real HW clock management per HSI channel, this is only
* virtual to keep track of active channels and ease debug
*
* Function to be called with lock
*/
void hsi_clocks_disable_channel(struct device *dev, u8 channel_number,
				const char *s)
{
	struct platform_device *pd = to_platform_device(dev);
	struct hsi_dev *hsi_ctrl = platform_get_drvdata(pd);

	if (channel_number != HSI_CH_NUMBER_NONE)
		dev_dbg(dev, "CLK: hsi_clocks_disable for "
			"channel %d: %s\n", channel_number, s);
	else
		dev_dbg(dev, "CLK: hsi_clocks_disable: %s\n", s);

	if (!hsi_ctrl->clock_enabled) {
		dev_dbg(dev, "Clocks already disabled, skipping...\n");
		return;
	}
	if (hsi_is_hsi_controller_busy(hsi_ctrl)) {
		dev_dbg(dev, "Cannot disable clocks, HSI port busy\n");
		return;
	}

	if (hsi_is_hst_controller_busy(hsi_ctrl))
		dev_warn(dev, "Disabling clocks with HST FSM not IDLE !\n");

#ifndef USE_PM_RUNTIME_FOR_HSI
	hsi_runtime_suspend(dev);
	omap_device_idle(pd);
#else
	/* HSI_TODO : this can probably be changed
	 * to return pm_runtime_put(dev);
	 */
	pm_runtime_put_sync(dev);
#endif
}
static int _od_suspend_noirq(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct omap_device *od = to_omap_device(pdev);
	int ret;

	/* Don't attempt late suspend on a driver that is not bound */
	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
		return 0;

	ret = pm_generic_suspend_noirq(dev);

	if (!ret && !pm_runtime_status_suspended(dev)) {
		if (pm_generic_runtime_suspend(dev) == 0) {
			if (!pm_runtime_suspended(dev)) {
				/* NOTE: *might* indicate driver race */
				dev_dbg(dev, "%s: Force suspending\n",
					__func__);
				pm_runtime_set_suspended(dev);
				od->flags |= OMAP_DEVICE_SUSPEND_FORCED;
			}
			omap_device_idle(pdev);
			od->flags |= OMAP_DEVICE_SUSPENDED;
		}
	}

	return ret;
}
Esempio n. 3
0
/**
 * omap_device_late_idle - idle devices without drivers
 * @dev: struct device * associated with omap_device
 * @data: unused
 *
 * Check the driver bound status of this device, and idle it
 * if there is no driver attached.
 */
static int __init omap_device_late_idle(struct device *dev, void *data)
{
    struct platform_device *pdev = to_platform_device(dev);
    struct omap_device *od = to_omap_device(pdev);
    int i;

    if (!od)
        return 0;

    /*
     * If omap_device state is enabled, but has no driver bound,
     * idle it.
     */

    /*
     * Some devices (like memory controllers) are always kept
     * enabled, and should not be idled even with no drivers.
     */
    for (i = 0; i < od->hwmods_cnt; i++)
        if (od->hwmods[i]->flags & HWMOD_INIT_NO_IDLE)
            return 0;

    if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
        if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
            dev_warn(dev, "%s: enabled but no driver.  Idling\n",
                     __func__);
            omap_device_idle(pdev);
        }
    }

    return 0;
}
Esempio n. 4
0
static int rpres_fdif_shutdown(struct platform_device *pdev)
{
	struct rpres_platform_data *pdata = pdev->dev.platform_data;

	omap_hwmod_reset(pdata->oh);

	return omap_device_idle(pdev);
}
Esempio n. 5
0
static int _od_runtime_suspend(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	int ret;

	ret = pm_generic_runtime_suspend(dev);
	if (ret)
		return ret;

	return omap_device_idle(pdev);
}
Esempio n. 6
0
static int rpres_iss_shutdown(struct platform_device *pdev)
{
	int ret;
	struct rpres_platform_data *pdata = pdev->dev.platform_data;

	omap_hwmod_reset(pdata->oh);

	ret = omap_device_idle(pdev);
	if (!ret)
		_disable_optional_clocks(pdata->oh);

	return ret;
}
Esempio n. 7
0
static int sr_put(struct omap_sr *sr)
{
	int r;

	if (sr->suspended)
		r = omap_device_idle(sr->pdev);
	else
		r = pm_runtime_put_sync_suspend(&sr->pdev->dev);
	if (r < 0)
		dev_err(&sr->pdev->dev, "%s: failed:%d susp=%d\n",
			__func__, r, sr->suspended);
	return r;
}
Esempio n. 8
0
int omap_pm_runtime_suspend(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	int r, ret = 0;

	dev_dbg(dev, "%s\n", __func__);

	ret = pm_generic_runtime_suspend(dev);

	if (!ret && dev->parent == &omap_device_parent) {
		r = omap_device_idle(pdev);
		WARN_ON(r);
	}

	return ret;
};
Esempio n. 9
0
int omap2430_async_suspend(struct musb *musb)
{
	struct platform_device *pdev
		= to_platform_device(musb->controller->parent);
	unsigned long flags = 0;
	int ret = 0;
	if (!pdev) {
		pr_err("%s pdev is null error\n", __func__);
		return -ENODEV;
	}

	dev_info(&pdev->dev, "%s async_resume %d +\n",
		__func__, musb->async_resume);

	mutex_lock(&musb->async_musb_lock);

	do {
		musb->async_resume--;
	} while (musb->reserve_async_suspend-- > 0);
	musb->reserve_async_suspend = 0;

	if (musb->async_resume > 0)
		;
	else if (musb->async_resume < 0) {
		musb->async_resume++;
		dev_err(&pdev->dev, "%s async_resume is fault\n", __func__);
	} else {
		spin_lock_irqsave(&musb->lock, flags);
		musb_async_suspend(musb);
		omap2430_low_level_exit(musb);
		otg_set_suspend(musb->xceiv, 1);
		spin_unlock_irqrestore(&musb->lock, flags);
		ret = omap_device_idle(pdev);
		if (ret < 0) {
			dev_err(&pdev->dev, "%s omap_device_idle error ret=%d\n",
				__func__, ret);
			mutex_unlock(&musb->async_musb_lock);
			return ret;
		}
	}
	mutex_unlock(&musb->async_musb_lock);
	dev_info(&pdev->dev, "%s async_resume %d -\n",
		__func__, musb->async_resume);
	return 0;
}
Esempio n. 10
0
static int _od_suspend_noirq(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct omap_device *od = to_omap_device(pdev);
	int ret;

	ret = pm_generic_suspend_noirq(dev);

	if (!ret && !pm_runtime_status_suspended(dev)) {
		if (pm_generic_runtime_suspend(dev) == 0) {
			if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
				omap_device_idle(pdev);
			od->flags |= OMAP_DEVICE_SUSPENDED;
		}
	}

	return ret;
}
/**
* omap_hsi_prepare_idle - Prepare HSI for idle to low power
*
* Return value : -ENODEV if HSI controller has not been found, else 0.
*
*/
int omap_hsi_prepare_idle(void)
{
	struct platform_device *pdev;
	struct hsi_dev *hsi_ctrl;

	pdev = hsi_get_hsi_platform_device();
	hsi_ctrl = hsi_get_hsi_controller_data(pdev);

	if (!hsi_ctrl)
		return -ENODEV;

	/* If hsi_clocks_disable_channel() is used, it prevents board to */
	/* enter sleep, due to the checks of HSI controller status. */
	/* This is why we call directly the omap_device_xxx() function here */
	hsi_runtime_suspend(hsi_ctrl->dev);
	omap_device_idle(pdev);

	return 0;
}
Esempio n. 12
0
/**
* hsi_clocks_disable_channel - virtual wrapper for disabling HSI clocks for
* a given channel
* @dev - reference to the hsi device.
* @channel_number - channel number which requests clock to be disabled
*		    0xFF means no particular channel
*
* Note : there is no real HW clock management per HSI channel, this is only
* virtual to keep track of active channels and ease debug
*
* Function to be called with lock
*/
void hsi_clocks_disable_channel(struct device *dev, u8 channel_number,
				const char *s)
{
	struct platform_device *pd = to_platform_device(dev);
	struct hsi_dev *hsi_ctrl = platform_get_drvdata(pd);

	if (channel_number != HSI_CH_NUMBER_NONE)
		dev_dbg(dev, "CLK: hsi_clocks_disable for "
			"channel %d: %s\n", channel_number, s);
	else
		dev_dbg(dev, "CLK: hsi_clocks_disable: %s\n", s);

	if (!hsi_ctrl->clock_enabled) {
		dev_dbg(dev, "Clocks already disabled, skipping...\n");
		return;
	}
	if (hsi_is_hsi_controller_busy(hsi_ctrl)) {
		dev_dbg(dev, "Cannot disable clocks, HSI port busy\n");
		return;
	}

	if (hsi_is_hst_controller_busy(hsi_ctrl))
/* MIPI Unstable Downlink Throughput : Disable log ( dev_warn = >  dev_dbg) */
#if 1
		dev_dbg(dev, "Disabling clocks with HST FSM not IDLE !\n");
#endif

#ifdef CONFIG_PM
	/* Allow Fclk to change */
	if (dpll_cascading_blocker_release(dev) < 0)
		dev_warn(dev, "Error releasing DPLL cascading constraint\n");
#endif /* CONFIG_PM */

#ifndef USE_PM_RUNTIME_FOR_HSI
	hsi_runtime_suspend(dev);
	omap_device_idle(pd);
#else
	/* HSI_TODO : this can probably be changed
	 * to return pm_runtime_put(dev);
	 */
	pm_runtime_put_sync(dev);
#endif
}
Esempio n. 13
0
static int _omap_device_notifier_call(struct notifier_block *nb,
				      unsigned long event, void *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct omap_device *od;
	int err;

	switch (event) {
	case BUS_NOTIFY_REMOVED_DEVICE:
		if (pdev->archdata.od)
			omap_device_delete(pdev->archdata.od);
		break;
	case BUS_NOTIFY_UNBOUND_DRIVER:
		od = to_omap_device(pdev);
		if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED)) {
			dev_info(dev, "enabled after unload, idling\n");
			err = omap_device_idle(pdev);
			if (err)
				dev_err(dev, "failed to idle\n");
		}
		break;
	case BUS_NOTIFY_BIND_DRIVER:
		od = to_omap_device(pdev);
		if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED) &&
		    pm_runtime_status_suspended(dev)) {
			od->_driver_status = BUS_NOTIFY_BIND_DRIVER;
			pm_runtime_set_active(dev);
		}
		break;
	case BUS_NOTIFY_ADD_DEVICE:
		if (pdev->dev.of_node)
			omap_device_build_from_dt(pdev);
		omap_auxdata_legacy_init(dev);
		/* fall through */
	default:
		od = to_omap_device(pdev);
		if (od)
			od->_driver_status = event;
	}

	return NOTIFY_DONE;
}
Esempio n. 14
0
static int _od_suspend_noirq(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct omap_device *od = to_omap_device(pdev);
	int ret;

	/* Don't attempt late suspend on a driver that is not bound */
	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
		return 0;

	ret = pm_generic_suspend_noirq(dev);

	if (!ret && !pm_runtime_status_suspended(dev)) {
		if (pm_generic_runtime_suspend(dev) == 0) {
			omap_device_idle(pdev);
			od->flags |= OMAP_DEVICE_SUSPENDED;
		}
	}

	return ret;
}
Esempio n. 15
0
/**
 * omap_device_late_idle - idle devices without drivers
 * @dev: struct device * associated with omap_device
 * @data: unused
 *
 * Check the driver bound status of this device, and idle it
 * if there is no driver attached.
 */
static int __init omap_device_late_idle(struct device *dev, void *data)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct omap_device *od = to_omap_device(pdev);

	if (!od)
		return 0;

	/*
	 * If omap_device state is enabled, but has no driver bound,
	 * idle it.
	 */
	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
		if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
			dev_warn(dev, "%s: enabled but no driver.  Idling\n",
				 __func__);
			omap_device_idle(pdev);
		}
	}

	return 0;
}
Esempio n. 16
0
static inline int omap_rproc_stop(struct rproc *rproc)
{
	struct device *dev = rproc->dev;
	struct platform_device *pdev = to_platform_device(dev);
	struct omap_rproc_pdata *pdata = dev->platform_data;
	struct omap_rproc_timers_info *timers = pdata->timers;
	int ret, i;

#ifdef CONFIG_REMOTE_PROC_AUTOSUSPEND
	_destroy_pm_flags(rproc);
#endif
	if (rproc->secure_reset) {
		ret = rproc_drm_invoke_service(false);
		if (ret)
			dev_err(rproc->dev, "rproc_drm_invoke_service failed "
					"for secure disable ret = 0x%x\n", ret);
		rproc->secure_reset = false;
	}

	ret = omap_device_idle(pdev);
	if (ret)
		goto err;

	for (i = 0; i < pdata->timers_cnt; i++) {
#ifdef CONFIG_REMOTEPROC_WATCHDOG
		/* GPT 9 & 11 (ipu); GPT 6 (dsp) are used as watchdog timers */
		if ((!strcmp(rproc->name, "dsp") && timers[i].id == 6) ||
		    (!strcmp(rproc->name, "ipu") &&
				(timers[i].id == DUCATI_WDT_TIMER_1 || timers[i].id == DUCATI_WDT_TIMER_2)))
			free_irq(omap_dm_timer_get_irq(timers[i].odt), rproc);
#endif
		omap_dm_timer_free(timers[i].odt);
		timers[i].odt = NULL;
	}
err:
	return ret;
}
Esempio n. 17
0
static int _od_runtime_suspend(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);

	return omap_device_idle(pdev);
}