|
@@ -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;
|