|  | @@ -772,3 +772,197 @@ odbs_exit:
 | 
	
		
			
				|  |  |  	pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	return ERR_PTR(ret);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * omap_early_device_register - register an omap_device as an early platform
 | 
	
		
			
				|  |  | + * device.
 | 
	
		
			
				|  |  | + * @od: struct omap_device * to register
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Register the omap_device structure.  This currently just calls
 | 
	
		
			
				|  |  | + * platform_early_add_device() on the underlying platform_device.
 | 
	
		
			
				|  |  | + * Returns 0 by default.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +static int __init omap_early_device_register(struct platform_device *pdev)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct platform_device *devices[1];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	devices[0] = pdev;
 | 
	
		
			
				|  |  | +	early_platform_add_devices(devices, 1);
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifdef CONFIG_PM_RUNTIME
 | 
	
		
			
				|  |  | +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)
 | 
	
		
			
				|  |  | +		omap_device_idle(pdev);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return ret;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int _od_runtime_idle(struct device *dev)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	return pm_generic_runtime_idle(dev);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int _od_runtime_resume(struct device *dev)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct platform_device *pdev = to_platform_device(dev);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	omap_device_enable(pdev);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return pm_generic_runtime_resume(dev);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#ifdef CONFIG_SUSPEND
 | 
	
		
			
				|  |  | +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 (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
 | 
	
		
			
				|  |  | +				omap_device_idle(pdev);
 | 
	
		
			
				|  |  | +			od->flags |= OMAP_DEVICE_SUSPENDED;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return ret;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int _od_resume_noirq(struct device *dev)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct platform_device *pdev = to_platform_device(dev);
 | 
	
		
			
				|  |  | +	struct omap_device *od = to_omap_device(pdev);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if ((od->flags & OMAP_DEVICE_SUSPENDED) &&
 | 
	
		
			
				|  |  | +	    !pm_runtime_status_suspended(dev)) {
 | 
	
		
			
				|  |  | +		od->flags &= ~OMAP_DEVICE_SUSPENDED;
 | 
	
		
			
				|  |  | +		if (!(od->flags & OMAP_DEVICE_NO_IDLE_ON_SUSPEND))
 | 
	
		
			
				|  |  | +			omap_device_enable(pdev);
 | 
	
		
			
				|  |  | +		pm_generic_runtime_resume(dev);
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return pm_generic_resume_noirq(dev);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +#define _od_suspend_noirq NULL
 | 
	
		
			
				|  |  | +#define _od_resume_noirq NULL
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +struct dev_pm_domain omap_device_pm_domain = {
 | 
	
		
			
				|  |  | +	.ops = {
 | 
	
		
			
				|  |  | +		SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
 | 
	
		
			
				|  |  | +				   _od_runtime_idle)
 | 
	
		
			
				|  |  | +		USE_PLATFORM_PM_SLEEP_OPS
 | 
	
		
			
				|  |  | +		.suspend_noirq = _od_suspend_noirq,
 | 
	
		
			
				|  |  | +		.resume_noirq = _od_resume_noirq,
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * omap_device_register - register an omap_device with one omap_hwmod
 | 
	
		
			
				|  |  | + * @od: struct omap_device * to register
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Register the omap_device structure.  This currently just calls
 | 
	
		
			
				|  |  | + * platform_device_register() on the underlying platform_device.
 | 
	
		
			
				|  |  | + * Returns the return value of platform_device_register().
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +int omap_device_register(struct platform_device *pdev)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	pr_debug("omap_device: %s: registering\n", pdev->name);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	pdev->dev.pm_domain = &omap_device_pm_domain;
 | 
	
		
			
				|  |  | +	return platform_device_add(pdev);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Public functions for use by device drivers through struct platform_data */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * omap_device_enable - fully activate an omap_device
 | 
	
		
			
				|  |  | + * @od: struct omap_device * to activate
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Do whatever is necessary for the hwmods underlying omap_device @od
 | 
	
		
			
				|  |  | + * to be accessible and ready to operate.  This generally involves
 | 
	
		
			
				|  |  | + * enabling clocks, setting SYSCONFIG registers; and in the future may
 | 
	
		
			
				|  |  | + * involve remuxing pins.  Device drivers should call this function
 | 
	
		
			
				|  |  | + * (through platform_data function pointers) where they would normally
 | 
	
		
			
				|  |  | + * enable clocks, etc.  Returns -EINVAL if called when the omap_device
 | 
	
		
			
				|  |  | + * is already enabled, or passes along the return value of
 | 
	
		
			
				|  |  | + * _omap_device_activate().
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +int omap_device_enable(struct platform_device *pdev)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int ret;
 | 
	
		
			
				|  |  | +	struct omap_device *od;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	od = to_omap_device(pdev);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
 | 
	
		
			
				|  |  | +		dev_warn(&pdev->dev,
 | 
	
		
			
				|  |  | +			 "omap_device: %s() called from invalid state %d\n",
 | 
	
		
			
				|  |  | +			 __func__, od->_state);
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/* Enable everything if we're enabling this device from scratch */
 | 
	
		
			
				|  |  | +	if (od->_state == OMAP_DEVICE_STATE_UNKNOWN)
 | 
	
		
			
				|  |  | +		od->pm_lat_level = od->pm_lats_cnt;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = _omap_device_activate(od, IGNORE_WAKEUP_LAT);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	od->dev_wakeup_lat = 0;
 | 
	
		
			
				|  |  | +	od->_dev_wakeup_lat_limit = UINT_MAX;
 | 
	
		
			
				|  |  | +	od->_state = OMAP_DEVICE_STATE_ENABLED;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return ret;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * omap_device_idle - idle an omap_device
 | 
	
		
			
				|  |  | + * @od: struct omap_device * to idle
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Idle omap_device @od by calling as many .deactivate_func() entries
 | 
	
		
			
				|  |  | + * in the omap_device's pm_lats table as is possible without exceeding
 | 
	
		
			
				|  |  | + * the device's maximum wakeup latency limit, pm_lat_limit.  Device
 | 
	
		
			
				|  |  | + * drivers should call this function (through platform_data function
 | 
	
		
			
				|  |  | + * pointers) where they would normally disable clocks after operations
 | 
	
		
			
				|  |  | + * complete, etc..  Returns -EINVAL if the omap_device is not
 | 
	
		
			
				|  |  | + * currently enabled, or passes along the return value of
 | 
	
		
			
				|  |  | + * _omap_device_deactivate().
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +int omap_device_idle(struct platform_device *pdev)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	int ret;
 | 
	
		
			
				|  |  | +	struct omap_device *od;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	od = to_omap_device(pdev);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
 | 
	
		
			
				|  |  | +		dev_warn(&pdev->dev,
 | 
	
		
			
				|  |  | +			 "omap_device: %s() called from invalid state %d\n",
 | 
	
		
			
				|  |  | +			 __func__, od->_state);
 | 
	
		
			
				|  |  | +		return -EINVAL;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	ret = _omap_device_deactivate(od, USE_WAKEUP_LAT);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	od->_state = OMAP_DEVICE_STATE_IDLE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	return ret;
 |