subsystem-level callbacks. Specifically, if a device's pm_domain pointer is
not NULL, the ->suspend() callback from the object pointed to by it will be
executed instead of its subsystem's (e.g. bus type's) ->suspend() callback and
-anlogously for all of the remaining callbacks. In other words, power management
-domain callbacks, if defined for the given device, always take precedence over
-the callbacks provided by the device's subsystem (e.g. bus type).
+analogously for all of the remaining callbacks. In other words, power
+management domain callbacks, if defined for the given device, always take
+precedence over the callbacks provided by the device's subsystem (e.g. bus
+type).
The support for device power management domains is only relevant to platforms
needing to use the same device driver power management callbacks in many
Device Low Power (suspend) States
---------------------------------
Device low-power states aren't standard. One device might only handle
-"on" and "off, while another might support a dozen different versions of
+"on" and "off", while another might support a dozen different versions of
"on" (how many engines are active?), plus a state that gets back to "on"
faster than from a full "off".
return 0;
}
-static int xo15_sci_resume(struct acpi_device *device)
+static int xo15_sci_resume(struct device *dev)
{
/* Enable all EC events */
olpc_ec_mask_write(EC_SCI_SRC_ALL);
return 0;
}
+static SIMPLE_DEV_PM_OPS(xo15_sci_pm, NULL, xo15_sci_resume);
+
static const struct acpi_device_id xo15_sci_device_ids[] = {
{"XO15EC", 0},
{"", 0},
.ops = {
.add = xo15_sci_add,
.remove = xo15_sci_remove,
- .resume = xo15_sci_resume,
},
+ .drv.pm = &xo15_sci_pm,
};
static int __init xo15_sci_init(void)
static int acpi_ac_add(struct acpi_device *device);
static int acpi_ac_remove(struct acpi_device *device, int type);
-static int acpi_ac_resume(struct acpi_device *device);
static void acpi_ac_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id ac_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, ac_device_ids);
+static int acpi_ac_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
+
static struct acpi_driver acpi_ac_driver = {
.name = "ac",
.class = ACPI_AC_CLASS,
.ops = {
.add = acpi_ac_add,
.remove = acpi_ac_remove,
- .resume = acpi_ac_resume,
.notify = acpi_ac_notify,
},
+ .drv.pm = &acpi_ac_pm,
};
struct acpi_ac {
return result;
}
-static int acpi_ac_resume(struct acpi_device *device)
+static int acpi_ac_resume(struct device *dev)
{
struct acpi_ac *ac;
unsigned old_state;
- if (!device || !acpi_driver_data(device))
+
+ if (!dev)
return -EINVAL;
- ac = acpi_driver_data(device);
+
+ ac = acpi_driver_data(to_acpi_device(dev));
+ if (!ac)
+ return -EINVAL;
+
old_state = ac->state;
if (acpi_ac_get_state(ac))
return 0;
}
/* this is needed to learn about changes made in suspended state */
-static int acpi_battery_resume(struct acpi_device *device)
+static int acpi_battery_resume(struct device *dev)
{
struct acpi_battery *battery;
- if (!device)
+
+ if (!dev)
return -EINVAL;
- battery = acpi_driver_data(device);
+
+ battery = acpi_driver_data(to_acpi_device(dev));
+ if (!battery)
+ return -EINVAL;
+
battery->update_time = 0;
acpi_battery_update(battery);
return 0;
}
+static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
+
static struct acpi_driver acpi_battery_driver = {
.name = "battery",
.class = ACPI_BATTERY_CLASS,
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
.ops = {
.add = acpi_battery_add,
- .resume = acpi_battery_resume,
.remove = acpi_battery_remove,
.notify = acpi_battery_notify,
},
+ .drv.pm = &acpi_battery_pm,
};
static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
static int acpi_button_add(struct acpi_device *device);
static int acpi_button_remove(struct acpi_device *device, int type);
-static int acpi_button_resume(struct acpi_device *device);
static void acpi_button_notify(struct acpi_device *device, u32 event);
+static int acpi_button_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume);
+
static struct acpi_driver acpi_button_driver = {
.name = "button",
.class = ACPI_BUTTON_CLASS,
.ids = button_device_ids,
.ops = {
.add = acpi_button_add,
- .resume = acpi_button_resume,
.remove = acpi_button_remove,
.notify = acpi_button_notify,
},
+ .drv.pm = &acpi_button_pm,
};
struct acpi_button {
}
}
-static int acpi_button_resume(struct acpi_device *device)
+static int acpi_button_resume(struct device *dev)
{
+ struct acpi_device *device = to_acpi_device(dev);
struct acpi_button *button = acpi_driver_data(device);
if (button->type == ACPI_BUTTON_TYPE_LID)
static int acpi_fan_add(struct acpi_device *device);
static int acpi_fan_remove(struct acpi_device *device, int type);
-static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
-static int acpi_fan_resume(struct acpi_device *device);
static const struct acpi_device_id fan_device_ids[] = {
{"PNP0C0B", 0},
};
MODULE_DEVICE_TABLE(acpi, fan_device_ids);
+static int acpi_fan_suspend(struct device *dev);
+static int acpi_fan_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume);
+
static struct acpi_driver acpi_fan_driver = {
.name = "fan",
.class = ACPI_FAN_CLASS,
.ops = {
.add = acpi_fan_add,
.remove = acpi_fan_remove,
- .suspend = acpi_fan_suspend,
- .resume = acpi_fan_resume,
},
+ .drv.pm = &acpi_fan_pm,
};
/* thermal cooling device callbacks */
return 0;
}
-static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
+static int acpi_fan_suspend(struct device *dev)
{
- if (!device)
+ if (!dev)
return -EINVAL;
- acpi_bus_set_power(device->handle, ACPI_STATE_D0);
+ acpi_bus_set_power(to_acpi_device(dev)->handle, ACPI_STATE_D0);
return AE_OK;
}
-static int acpi_fan_resume(struct acpi_device *device)
+static int acpi_fan_resume(struct device *dev)
{
int result;
- if (!device)
+ if (!dev)
return -EINVAL;
- result = acpi_bus_update_power(device->handle, NULL);
+ result = acpi_bus_update_power(to_acpi_device(dev)->handle, NULL);
if (result)
printk(KERN_ERR PREFIX "Error updating fan power state\n");
static int acpi_power_add(struct acpi_device *device);
static int acpi_power_remove(struct acpi_device *device, int type);
-static int acpi_power_resume(struct acpi_device *device);
static const struct acpi_device_id power_device_ids[] = {
{ACPI_POWER_HID, 0},
};
MODULE_DEVICE_TABLE(acpi, power_device_ids);
+static int acpi_power_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_power_pm, NULL, acpi_power_resume);
+
static struct acpi_driver acpi_power_driver = {
.name = "power",
.class = ACPI_POWER_CLASS,
.ops = {
.add = acpi_power_add,
.remove = acpi_power_remove,
- .resume = acpi_power_resume,
},
+ .drv.pm = &acpi_power_pm,
};
/*
return 0;
}
-static int acpi_power_resume(struct acpi_device *device)
+static int acpi_power_resume(struct device *dev)
{
int result = 0, state;
+ struct acpi_device *device;
struct acpi_power_resource *resource;
- if (!device)
+ if (!dev)
return -EINVAL;
+ device = to_acpi_device(dev);
resource = acpi_driver_data(device);
if (!resource)
return -EINVAL;
};
MODULE_DEVICE_TABLE(acpi, processor_device_ids);
+static SIMPLE_DEV_PM_OPS(acpi_processor_pm,
+ acpi_processor_suspend, acpi_processor_resume);
+
static struct acpi_driver acpi_processor_driver = {
.name = "processor",
.class = ACPI_PROCESSOR_CLASS,
.ops = {
.add = acpi_processor_add,
.remove = acpi_processor_remove,
- .suspend = acpi_processor_suspend,
- .resume = acpi_processor_resume,
.notify = acpi_processor_notify,
},
+ .drv.pm = &acpi_processor_pm,
};
#define INSTALL_NOTIFY_HANDLER 1
* Initialize missing things
*/
if (pr->flags.need_hotplug_init) {
- struct cpuidle_driver *idle_driver =
- cpuidle_get_driver();
-
printk(KERN_INFO "Will online and init hotplugged "
"CPU: %d\n", pr->id);
WARN(acpi_processor_start(pr), "Failed to start CPU:"
" %d\n", pr->id);
pr->flags.need_hotplug_init = 0;
- if (idle_driver && !strcmp(idle_driver->name,
- "intel_idle")) {
- intel_idle_cpu_init(pr->id);
- }
/* Normal CPU soft online event */
} else {
acpi_processor_ppc_has_changed(pr, 0);
#endif
-/*
- * Suspend / resume control
- */
-static int acpi_idle_suspend;
static u32 saved_bm_rld;
static void acpi_idle_bm_rld_save(void)
acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, saved_bm_rld);
}
-int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
+int acpi_processor_suspend(struct device *dev)
{
- if (acpi_idle_suspend == 1)
- return 0;
-
acpi_idle_bm_rld_save();
- acpi_idle_suspend = 1;
return 0;
}
-int acpi_processor_resume(struct acpi_device * device)
+int acpi_processor_resume(struct device *dev)
{
- if (acpi_idle_suspend == 0)
- return 0;
-
acpi_idle_bm_rld_restore();
- acpi_idle_suspend = 0;
return 0;
}
*/
cx->valid = 1;
- cx->latency_ticks = cx->latency;
/*
* On older chipsets, BM_RLD needs to be set
* in order for Bus Master activity to wake the
if (!cx->address)
break;
cx->valid = 1;
- cx->latency_ticks = cx->latency; /* Normalize latency */
break;
case ACPI_STATE_C3:
local_irq_disable();
- if (acpi_idle_suspend) {
- local_irq_enable();
- cpu_relax();
- return -EBUSY;
- }
lapic_timer_state_broadcast(pr, cx, 1);
kt1 = ktime_get_real();
dev->last_residency = (int)idle_time;
local_irq_enable();
- cx->usage++;
lapic_timer_state_broadcast(pr, cx, 0);
return index;
local_irq_disable();
- if (acpi_idle_suspend) {
- local_irq_enable();
- cpu_relax();
- return -EBUSY;
- }
if (cx->entry_method != ACPI_CSTATE_FFH) {
current_thread_info()->status &= ~TS_POLLING;
if (cx->entry_method != ACPI_CSTATE_FFH)
current_thread_info()->status |= TS_POLLING;
- cx->usage++;
-
lapic_timer_state_broadcast(pr, cx, 0);
- cx->time += idle_time;
return index;
}
drv, drv->safe_state_index);
} else {
local_irq_disable();
- if (!acpi_idle_suspend)
- acpi_safe_halt();
+ acpi_safe_halt();
local_irq_enable();
return -EBUSY;
}
local_irq_disable();
- if (acpi_idle_suspend) {
- local_irq_enable();
- cpu_relax();
- return -EBUSY;
- }
if (cx->entry_method != ACPI_CSTATE_FFH) {
current_thread_info()->status &= ~TS_POLLING;
if (cx->entry_method != ACPI_CSTATE_FFH)
current_thread_info()->status |= TS_POLLING;
- cx->usage++;
-
lapic_timer_state_broadcast(pr, cx, 0);
- cx->time += idle_time;
return index;
}
#endif
}
-static int acpi_sbs_resume(struct acpi_device *device)
+static int acpi_sbs_resume(struct device *dev)
{
struct acpi_sbs *sbs;
- if (!device)
+ if (!dev)
return -EINVAL;
- sbs = device->driver_data;
+ sbs = to_acpi_device(dev)->driver_data;
acpi_sbs_callback(sbs);
return 0;
}
+static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume);
+
static struct acpi_driver acpi_sbs_driver = {
.name = "sbs",
.class = ACPI_SBS_CLASS,
.ops = {
.add = acpi_sbs_add,
.remove = acpi_sbs_remove,
- .resume = acpi_sbs_resume,
},
+ .drv.pm = &acpi_sbs_pm,
};
static int __init acpi_sbs_init(void)
kfree(acpi_dev);
}
-static int acpi_device_suspend(struct device *dev, pm_message_t state)
-{
- struct acpi_device *acpi_dev = to_acpi_device(dev);
- struct acpi_driver *acpi_drv = acpi_dev->driver;
-
- if (acpi_drv && acpi_drv->ops.suspend)
- return acpi_drv->ops.suspend(acpi_dev, state);
- return 0;
-}
-
-static int acpi_device_resume(struct device *dev)
-{
- struct acpi_device *acpi_dev = to_acpi_device(dev);
- struct acpi_driver *acpi_drv = acpi_dev->driver;
-
- if (acpi_drv && acpi_drv->ops.resume)
- return acpi_drv->ops.resume(acpi_dev);
- return 0;
-}
-
static int acpi_bus_match(struct device *dev, struct device_driver *drv)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
struct bus_type acpi_bus_type = {
.name = "acpi",
- .suspend = acpi_device_suspend,
- .resume = acpi_device_resume,
.match = acpi_bus_match,
.probe = acpi_device_probe,
.remove = acpi_device_remove,
static int acpi_thermal_add(struct acpi_device *device);
static int acpi_thermal_remove(struct acpi_device *device, int type);
-static int acpi_thermal_resume(struct acpi_device *device);
static void acpi_thermal_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id thermal_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
+static int acpi_thermal_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
+
static struct acpi_driver acpi_thermal_driver = {
.name = "thermal",
.class = ACPI_THERMAL_CLASS,
.ops = {
.add = acpi_thermal_add,
.remove = acpi_thermal_remove,
- .resume = acpi_thermal_resume,
.notify = acpi_thermal_notify,
},
+ .drv.pm = &acpi_thermal_pm,
};
struct acpi_thermal_state {
return 0;
}
-static int acpi_thermal_resume(struct acpi_device *device)
+static int acpi_thermal_resume(struct device *dev)
{
- struct acpi_thermal *tz = NULL;
+ struct acpi_thermal *tz;
int i, j, power_state, result;
-
- if (!device || !acpi_driver_data(device))
+ if (!dev)
return -EINVAL;
- tz = acpi_driver_data(device);
+ tz = acpi_driver_data(to_acpi_device(dev));
+ if (!tz)
+ return -EINVAL;
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
if (!(&tz->trips.active[i]))
start_latency_ns, "start");
}
-static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
-{
- return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev,
- save_state_latency_ns, "state save");
-}
-
-static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
-{
- return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev,
- restore_state_latency_ns,
- "state restore");
-}
-
static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
{
bool ret = false;
genpd->status = GPD_STATE_ACTIVE;
}
+static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
+{
+ s64 usecs64;
+
+ if (!genpd->cpu_data)
+ return;
+
+ usecs64 = genpd->power_on_latency_ns;
+ do_div(usecs64, NSEC_PER_USEC);
+ usecs64 += genpd->cpu_data->saved_exit_latency;
+ genpd->cpu_data->idle_state->exit_latency = usecs64;
+}
+
/**
* __pm_genpd_poweron - Restore power to a given PM domain and its masters.
* @genpd: PM domain to power up.
* Restore power to @genpd and all of its masters so that it is possible to
* resume a device belonging to it.
*/
-int __pm_genpd_poweron(struct generic_pm_domain *genpd)
+static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
__releases(&genpd->lock) __acquires(&genpd->lock)
{
struct gpd_link *link;
return 0;
}
+ if (genpd->cpu_data) {
+ cpuidle_pause_and_lock();
+ genpd->cpu_data->idle_state->disabled = true;
+ cpuidle_resume_and_unlock();
+ goto out;
+ }
+
/*
* The list is guaranteed not to change while the loop below is being
* executed, unless one of the masters' .power_on() callbacks fiddles
if (elapsed_ns > genpd->power_on_latency_ns) {
genpd->power_on_latency_ns = elapsed_ns;
genpd->max_off_time_changed = true;
+ genpd_recalc_cpu_exit_latency(genpd);
if (genpd->name)
pr_warning("%s: Power-on latency exceeded, "
"new value %lld ns\n", genpd->name,
}
}
+ out:
genpd_set_active(genpd);
return 0;
#ifdef CONFIG_PM_RUNTIME
+static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev,
+ save_state_latency_ns, "state save");
+}
+
+static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
+{
+ return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev,
+ restore_state_latency_ns,
+ "state restore");
+}
+
static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
unsigned long val, void *ptr)
{
pdd = dev->power.subsys_data ?
dev->power.subsys_data->domain_data : NULL;
- if (pdd) {
+ if (pdd && pdd->dev) {
to_gpd_data(pdd)->td.constraint_changed = true;
genpd = dev_to_genpd(dev);
} else {
{
struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
struct device *dev = pdd->dev;
+ bool need_restore = gpd_data->need_restore;
- if (!gpd_data->need_restore)
- return;
-
+ gpd_data->need_restore = false;
mutex_unlock(&genpd->lock);
genpd_start_dev(genpd, dev);
- genpd_restore_dev(genpd, dev);
- genpd_stop_dev(genpd, dev);
+ if (need_restore)
+ genpd_restore_dev(genpd, dev);
mutex_lock(&genpd->lock);
-
- gpd_data->need_restore = false;
}
/**
}
}
+ if (genpd->cpu_data) {
+ /*
+ * If cpu_data is set, cpuidle should turn the domain off when
+ * the CPU in it is idle. In that case we don't decrement the
+ * subdomain counts of the master domains, so that power is not
+ * removed from the current domain prematurely as a result of
+ * cutting off the masters' power.
+ */
+ genpd->status = GPD_STATE_POWER_OFF;
+ cpuidle_pause_and_lock();
+ genpd->cpu_data->idle_state->disabled = false;
+ cpuidle_resume_and_unlock();
+ goto out;
+ }
+
if (genpd->power_off) {
ktime_t time_start;
s64 elapsed_ns;
/* If power.irq_safe, the PM domain is never powered off. */
if (dev->power.irq_safe)
- goto out;
+ return genpd_start_dev(genpd, dev);
mutex_lock(&genpd->lock);
ret = __pm_genpd_poweron(genpd);
wake_up_all(&genpd->status_wait_queue);
mutex_unlock(&genpd->lock);
- out:
- genpd_start_dev(genpd, dev);
-
return 0;
}
#endif /* CONFIG_PM_SLEEP */
+static struct generic_pm_domain_data *__pm_genpd_alloc_dev_data(struct device *dev)
+{
+ struct generic_pm_domain_data *gpd_data;
+
+ gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
+ if (!gpd_data)
+ return NULL;
+
+ mutex_init(&gpd_data->lock);
+ gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
+ dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+ return gpd_data;
+}
+
+static void __pm_genpd_free_dev_data(struct device *dev,
+ struct generic_pm_domain_data *gpd_data)
+{
+ dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+ kfree(gpd_data);
+}
+
/**
* __pm_genpd_add_device - Add a device to an I/O PM domain.
* @genpd: PM domain to add the device to.
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
struct gpd_timing_data *td)
{
- struct generic_pm_domain_data *gpd_data;
+ struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL;
struct pm_domain_data *pdd;
int ret = 0;
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
return -EINVAL;
- gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
- if (!gpd_data)
+ gpd_data_new = __pm_genpd_alloc_dev_data(dev);
+ if (!gpd_data_new)
return -ENOMEM;
- mutex_init(&gpd_data->lock);
- gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
- dev_pm_qos_add_notifier(dev, &gpd_data->nb);
-
genpd_acquire_lock(genpd);
if (genpd->prepared_count > 0) {
goto out;
}
+ ret = dev_pm_get_subsys_data(dev);
+ if (ret)
+ goto out;
+
genpd->device_count++;
genpd->max_off_time_changed = true;
- dev_pm_get_subsys_data(dev);
-
- mutex_lock(&gpd_data->lock);
spin_lock_irq(&dev->power.lock);
+
dev->pm_domain = &genpd->domain;
- dev->power.subsys_data->domain_data = &gpd_data->base;
- gpd_data->base.dev = dev;
- list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
- gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
+ if (dev->power.subsys_data->domain_data) {
+ gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+ } else {
+ gpd_data = gpd_data_new;
+ dev->power.subsys_data->domain_data = &gpd_data->base;
+ }
+ gpd_data->refcount++;
if (td)
gpd_data->td = *td;
+ spin_unlock_irq(&dev->power.lock);
+
+ mutex_lock(&gpd_data->lock);
+ gpd_data->base.dev = dev;
+ list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+ gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
gpd_data->td.constraint_changed = true;
gpd_data->td.effective_constraint_ns = -1;
- spin_unlock_irq(&dev->power.lock);
mutex_unlock(&gpd_data->lock);
- genpd_release_lock(genpd);
-
- return 0;
-
out:
genpd_release_lock(genpd);
- dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
- kfree(gpd_data);
+ if (gpd_data != gpd_data_new)
+ __pm_genpd_free_dev_data(dev, gpd_data_new);
+
return ret;
}
{
struct generic_pm_domain_data *gpd_data;
struct pm_domain_data *pdd;
+ bool remove = false;
int ret = 0;
dev_dbg(dev, "%s()\n", __func__);
genpd->max_off_time_changed = true;
spin_lock_irq(&dev->power.lock);
+
dev->pm_domain = NULL;
pdd = dev->power.subsys_data->domain_data;
list_del_init(&pdd->list_node);
- dev->power.subsys_data->domain_data = NULL;
+ gpd_data = to_gpd_data(pdd);
+ if (--gpd_data->refcount == 0) {
+ dev->power.subsys_data->domain_data = NULL;
+ remove = true;
+ }
+
spin_unlock_irq(&dev->power.lock);
- gpd_data = to_gpd_data(pdd);
mutex_lock(&gpd_data->lock);
pdd->dev = NULL;
mutex_unlock(&gpd_data->lock);
genpd_release_lock(genpd);
- dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
- kfree(gpd_data);
dev_pm_put_subsys_data(dev);
+ if (remove)
+ __pm_genpd_free_dev_data(dev, gpd_data);
+
return 0;
out:
* @dev: Device to add the callbacks to.
* @ops: Set of callbacks to add.
* @td: Timing data to add to the device along with the callbacks (optional).
+ *
+ * Every call to this routine should be balanced with a call to
+ * __pm_genpd_remove_callbacks() and they must not be nested.
*/
int pm_genpd_add_callbacks(struct device *dev, struct gpd_dev_ops *ops,
struct gpd_timing_data *td)
{
- struct pm_domain_data *pdd;
+ struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL;
int ret = 0;
- if (!(dev && dev->power.subsys_data && ops))
+ if (!(dev && ops))
return -EINVAL;
+ gpd_data_new = __pm_genpd_alloc_dev_data(dev);
+ if (!gpd_data_new)
+ return -ENOMEM;
+
pm_runtime_disable(dev);
device_pm_lock();
- pdd = dev->power.subsys_data->domain_data;
- if (pdd) {
- struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+ ret = dev_pm_get_subsys_data(dev);
+ if (ret)
+ goto out;
- gpd_data->ops = *ops;
- if (td)
- gpd_data->td = *td;
+ spin_lock_irq(&dev->power.lock);
+
+ if (dev->power.subsys_data->domain_data) {
+ gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
} else {
- ret = -EINVAL;
+ gpd_data = gpd_data_new;
+ dev->power.subsys_data->domain_data = &gpd_data->base;
}
+ gpd_data->refcount++;
+ gpd_data->ops = *ops;
+ if (td)
+ gpd_data->td = *td;
+
+ spin_unlock_irq(&dev->power.lock);
+ out:
device_pm_unlock();
pm_runtime_enable(dev);
+ if (gpd_data != gpd_data_new)
+ __pm_genpd_free_dev_data(dev, gpd_data_new);
+
return ret;
}
EXPORT_SYMBOL_GPL(pm_genpd_add_callbacks);
* __pm_genpd_remove_callbacks - Remove PM domain callbacks from a given device.
* @dev: Device to remove the callbacks from.
* @clear_td: If set, clear the device's timing data too.
+ *
+ * This routine can only be called after pm_genpd_add_callbacks().
*/
int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
{
- struct pm_domain_data *pdd;
+ struct generic_pm_domain_data *gpd_data = NULL;
+ bool remove = false;
int ret = 0;
if (!(dev && dev->power.subsys_data))
pm_runtime_disable(dev);
device_pm_lock();
- pdd = dev->power.subsys_data->domain_data;
- if (pdd) {
- struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
+ spin_lock_irq(&dev->power.lock);
- gpd_data->ops = (struct gpd_dev_ops){ 0 };
+ if (dev->power.subsys_data->domain_data) {
+ gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+ gpd_data->ops = (struct gpd_dev_ops){ NULL };
if (clear_td)
gpd_data->td = (struct gpd_timing_data){ 0 };
+
+ if (--gpd_data->refcount == 0) {
+ dev->power.subsys_data->domain_data = NULL;
+ remove = true;
+ }
} else {
ret = -EINVAL;
}
+ spin_unlock_irq(&dev->power.lock);
+
device_pm_unlock();
pm_runtime_enable(dev);
- return ret;
+ if (ret)
+ return ret;
+
+ dev_pm_put_subsys_data(dev);
+ if (remove)
+ __pm_genpd_free_dev_data(dev, gpd_data);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
+int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
+{
+ struct cpuidle_driver *cpuidle_drv;
+ struct gpd_cpu_data *cpu_data;
+ struct cpuidle_state *idle_state;
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(genpd) || state < 0)
+ return -EINVAL;
+
+ genpd_acquire_lock(genpd);
+
+ if (genpd->cpu_data) {
+ ret = -EEXIST;
+ goto out;
+ }
+ cpu_data = kzalloc(sizeof(*cpu_data), GFP_KERNEL);
+ if (!cpu_data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ cpuidle_drv = cpuidle_driver_ref();
+ if (!cpuidle_drv) {
+ ret = -ENODEV;
+ goto out;
+ }
+ if (cpuidle_drv->state_count <= state) {
+ ret = -EINVAL;
+ goto err;
+ }
+ idle_state = &cpuidle_drv->states[state];
+ if (!idle_state->disabled) {
+ ret = -EAGAIN;
+ goto err;
+ }
+ cpu_data->idle_state = idle_state;
+ cpu_data->saved_exit_latency = idle_state->exit_latency;
+ genpd->cpu_data = cpu_data;
+ genpd_recalc_cpu_exit_latency(genpd);
+
+ out:
+ genpd_release_lock(genpd);
+ return ret;
+
+ err:
+ cpuidle_driver_unref();
+ goto out;
+}
+
+int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+{
+ struct gpd_cpu_data *cpu_data;
+ struct cpuidle_state *idle_state;
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(genpd))
+ return -EINVAL;
+
+ genpd_acquire_lock(genpd);
+
+ cpu_data = genpd->cpu_data;
+ if (!cpu_data) {
+ ret = -ENODEV;
+ goto out;
+ }
+ idle_state = cpu_data->idle_state;
+ if (!idle_state->disabled) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ idle_state->exit_latency = cpu_data->saved_exit_latency;
+ cpuidle_driver_unref();
+ genpd->cpu_data = NULL;
+ kfree(cpu_data);
+
+ out:
+ genpd_release_lock(genpd);
+ return ret;
+}
+
/* Default device callbacks for generic PM domains. */
/**
static int pm_genpd_default_save_state(struct device *dev)
{
int (*cb)(struct device *__dev);
- struct device_driver *drv = dev->driver;
cb = dev_gpd_data(dev)->ops.save_state;
if (cb)
return cb(dev);
- if (drv && drv->pm && drv->pm->runtime_suspend)
- return drv->pm->runtime_suspend(dev);
+ if (dev->type && dev->type->pm)
+ cb = dev->type->pm->runtime_suspend;
+ else if (dev->class && dev->class->pm)
+ cb = dev->class->pm->runtime_suspend;
+ else if (dev->bus && dev->bus->pm)
+ cb = dev->bus->pm->runtime_suspend;
+ else
+ cb = NULL;
- return 0;
+ if (!cb && dev->driver && dev->driver->pm)
+ cb = dev->driver->pm->runtime_suspend;
+
+ return cb ? cb(dev) : 0;
}
/**
static int pm_genpd_default_restore_state(struct device *dev)
{
int (*cb)(struct device *__dev);
- struct device_driver *drv = dev->driver;
cb = dev_gpd_data(dev)->ops.restore_state;
if (cb)
return cb(dev);
- if (drv && drv->pm && drv->pm->runtime_resume)
- return drv->pm->runtime_resume(dev);
+ if (dev->type && dev->type->pm)
+ cb = dev->type->pm->runtime_resume;
+ else if (dev->class && dev->class->pm)
+ cb = dev->class->pm->runtime_resume;
+ else if (dev->bus && dev->bus->pm)
+ cb = dev->bus->pm->runtime_resume;
+ else
+ cb = NULL;
- return 0;
+ if (!cb && dev->driver && dev->driver->pm)
+ cb = dev->driver->pm->runtime_resume;
+
+ return cb ? cb(dev) : 0;
}
#ifdef CONFIG_PM_SLEEP
#include <linux/sched.h>
#include <linux/async.h>
#include <linux/suspend.h>
-
+#include <linux/cpuidle.h>
#include "../base.h"
#include "power.h"
mutex_unlock(&dpm_list_mtx);
dpm_show_time(starttime, state, "noirq");
resume_device_irqs();
+ cpuidle_resume();
}
/**
ktime_t starttime = ktime_get();
int error = 0;
+ cpuidle_pause();
suspend_device_irqs();
mutex_lock(&dpm_list_mtx);
while (!list_empty(&dpm_late_early_list)) {
static void __dev_pm_qos_drop_user_request(struct device *dev)
{
dev_pm_qos_remove_request(dev->power.pq_req);
- dev->power.pq_req = 0;
+ dev->power.pq_req = NULL;
}
/**
.getgeo = mg_getgeo
};
-static int mg_suspend(struct platform_device *plat_dev, pm_message_t state)
+static int mg_suspend(struct device *dev)
{
- struct mg_drv_data *prv_data = plat_dev->dev.platform_data;
+ struct mg_drv_data *prv_data = dev->platform_data;
struct mg_host *host = prv_data->host;
if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD))
return 0;
}
-static int mg_resume(struct platform_device *plat_dev)
+static int mg_resume(struct device *dev)
{
- struct mg_drv_data *prv_data = plat_dev->dev.platform_data;
+ struct mg_drv_data *prv_data = dev->platform_data;
struct mg_host *host = prv_data->host;
if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD))
return 0;
}
+static SIMPLE_DEV_PM_OPS(mg_pm, mg_suspend, mg_resume);
+
static int mg_probe(struct platform_device *plat_dev)
{
struct mg_host *host;
static struct platform_driver mg_disk_driver = {
.probe = mg_probe,
.remove = mg_remove,
- .suspend = mg_suspend,
- .resume = mg_resume,
.driver = {
.name = MG_DEV_NAME,
.owner = THIS_MODULE,
+ .pm = &mg_pm,
}
};
#ifdef CONFIG_PM
-static int omap_rng_suspend(struct platform_device *pdev, pm_message_t message)
+static int omap_rng_suspend(struct device *dev)
{
omap_rng_write_reg(RNG_MASK_REG, 0x0);
return 0;
}
-static int omap_rng_resume(struct platform_device *pdev)
+static int omap_rng_resume(struct device *dev)
{
omap_rng_write_reg(RNG_MASK_REG, 0x1);
return 0;
}
+static SIMPLE_DEV_PM_OPS(omap_rng_pm, omap_rng_suspend, omap_rng_resume);
+#define OMAP_RNG_PM (&omap_rng_pm)
+
#else
-#define omap_rng_suspend NULL
-#define omap_rng_resume NULL
+#define OMAP_RNG_PM NULL
#endif
.driver = {
.name = "omap_rng",
.owner = THIS_MODULE,
+ .pm = OMAP_RNG_PM,
},
.probe = omap_rng_probe,
.remove = __exit_p(omap_rng_remove),
- .suspend = omap_rng_suspend,
- .resume = omap_rng_resume
};
static int __init omap_rng_init(void)
cleanup_one_si(info);
}
-#ifdef CONFIG_PM
-static int ipmi_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- return 0;
-}
-
-static int ipmi_pci_resume(struct pci_dev *pdev)
-{
- return 0;
-}
-#endif
-
static struct pci_device_id ipmi_pci_devices[] = {
{ PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
{ PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) },
.id_table = ipmi_pci_devices,
.probe = ipmi_pci_probe,
.remove = __devexit_p(ipmi_pci_remove),
-#ifdef CONFIG_PM
- .suspend = ipmi_pci_suspend,
- .resume = ipmi_pci_resume,
-#endif
};
#endif /* CONFIG_PCI */
#ifdef CONFIG_PM
static int old_camera_power;
-static int sonypi_suspend(struct platform_device *dev, pm_message_t state)
+static int sonypi_suspend(struct device *dev)
{
old_camera_power = sonypi_device.camera_power;
sonypi_disable();
return 0;
}
-static int sonypi_resume(struct platform_device *dev)
+static int sonypi_resume(struct device *dev)
{
sonypi_enable(old_camera_power);
return 0;
}
+
+static SIMPLE_DEV_PM_OPS(sonypi_pm, sonypi_suspend, sonypi_resume);
+#define SONYPI_PM (&sonypi_pm)
#else
-#define sonypi_suspend NULL
-#define sonypi_resume NULL
+#define SONYPI_PM NULL
#endif
static void sonypi_shutdown(struct platform_device *dev)
.driver = {
.name = "sonypi",
.owner = THIS_MODULE,
+ .pm = SONYPI_PM,
},
.probe = sonypi_probe,
.remove = __devexit_p(sonypi_remove),
.shutdown = sonypi_shutdown,
- .suspend = sonypi_suspend,
- .resume = sonypi_resume,
};
static struct platform_device *sonypi_platform_device;
* We are about to suspend. Save the TPM state
* so that it can be restored.
*/
-int tpm_pm_suspend(struct device *dev, pm_message_t pm_state)
+int tpm_pm_suspend(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
struct tpm_cmd_t cmd;
loff_t *);
extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
extern void tpm_remove_hardware(struct device *);
-extern int tpm_pm_suspend(struct device *, pm_message_t);
+extern int tpm_pm_suspend(struct device *);
extern int tpm_pm_resume(struct device *);
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
wait_queue_head_t *);
}
}
-static int tpm_atml_suspend(struct platform_device *dev, pm_message_t msg)
-{
- return tpm_pm_suspend(&dev->dev, msg);
-}
+static SIMPLE_DEV_PM_OPS(tpm_atml_pm, tpm_pm_suspend, tpm_pm_resume);
-static int tpm_atml_resume(struct platform_device *dev)
-{
- return tpm_pm_resume(&dev->dev);
-}
static struct platform_driver atml_drv = {
.driver = {
.name = "tpm_atmel",
.owner = THIS_MODULE,
+ .pm = &tpm_atml_pm,
},
- .suspend = tpm_atml_suspend,
- .resume = tpm_atml_resume,
};
static int __init init_atmel(void)
}
}
-static int tpm_nsc_suspend(struct platform_device *dev, pm_message_t msg)
-{
- return tpm_pm_suspend(&dev->dev, msg);
-}
-
-static int tpm_nsc_resume(struct platform_device *dev)
-{
- return tpm_pm_resume(&dev->dev);
-}
+static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
static struct platform_driver nsc_drv = {
- .suspend = tpm_nsc_suspend,
- .resume = tpm_nsc_resume,
.driver = {
.name = "tpm_nsc",
.owner = THIS_MODULE,
+ .pm = &tpm_nsc_pm,
},
};
static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
{
- return tpm_pm_suspend(&dev->dev, msg);
+ return tpm_pm_suspend(&dev->dev);
}
static int tpm_tis_pnp_resume(struct pnp_dev *dev)
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
#endif
-static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg)
-{
- return tpm_pm_suspend(&dev->dev, msg);
-}
-static int tpm_tis_resume(struct platform_device *dev)
+static int tpm_tis_resume(struct device *dev)
{
- struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
+ struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip->vendor.irq)
tpm_tis_reenable_interrupts(chip);
- return tpm_pm_resume(&dev->dev);
+ return tpm_pm_resume(dev);
}
+
+static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
+
static struct platform_driver tis_drv = {
.driver = {
.name = "tpm_tis",
.owner = THIS_MODULE,
+ .pm = &tpm_tis_pm,
},
- .suspend = tpm_tis_suspend,
- .resume = tpm_tis_resume,
};
static struct platform_device *pdev;
EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock);
+/* Currently used in suspend/resume path to suspend cpuidle */
+void cpuidle_pause(void)
+{
+ mutex_lock(&cpuidle_lock);
+ cpuidle_uninstall_idle_handler();
+ mutex_unlock(&cpuidle_lock);
+}
+
+/* Currently used in suspend/resume path to resume cpuidle */
+void cpuidle_resume(void)
+{
+ mutex_lock(&cpuidle_lock);
+ cpuidle_install_idle_handler();
+ mutex_unlock(&cpuidle_lock);
+}
+
/**
* cpuidle_wrap_enter - performs timekeeping and irqen around enter function
* @dev: pointer to a valid cpuidle_device object
state->power_usage = -1;
state->flags = 0;
state->enter = poll_idle;
- state->disable = 0;
+ state->disabled = false;
}
#else
static void poll_idle_init(struct cpuidle_driver *drv) {}
static struct cpuidle_driver *cpuidle_curr_driver;
DEFINE_SPINLOCK(cpuidle_driver_lock);
+int cpuidle_driver_refcount;
static void __cpuidle_register_driver(struct cpuidle_driver *drv)
{
}
spin_lock(&cpuidle_driver_lock);
- cpuidle_curr_driver = NULL;
+
+ if (!WARN_ON(cpuidle_driver_refcount > 0))
+ cpuidle_curr_driver = NULL;
+
spin_unlock(&cpuidle_driver_lock);
}
EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
+
+struct cpuidle_driver *cpuidle_driver_ref(void)
+{
+ struct cpuidle_driver *drv;
+
+ spin_lock(&cpuidle_driver_lock);
+
+ drv = cpuidle_curr_driver;
+ cpuidle_driver_refcount++;
+
+ spin_unlock(&cpuidle_driver_lock);
+ return drv;
+}
+
+void cpuidle_driver_unref(void)
+{
+ spin_lock(&cpuidle_driver_lock);
+
+ if (!WARN_ON(cpuidle_driver_refcount <= 0))
+ cpuidle_driver_refcount--;
+
+ spin_unlock(&cpuidle_driver_lock);
+}
* unless the timer is happening really really soon.
*/
if (data->expected_us > 5 &&
- drv->states[CPUIDLE_DRIVER_STATE_START].disable == 0)
+ !drv->states[CPUIDLE_DRIVER_STATE_START].disabled &&
+ dev->states_usage[CPUIDLE_DRIVER_STATE_START].disable == 0)
data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
/*
*/
for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
+ struct cpuidle_state_usage *su = &dev->states_usage[i];
- if (s->disable)
+ if (s->disabled || su->disable)
continue;
if (s->target_residency > data->predicted_us)
continue;
struct attribute attr;
ssize_t (*show)(struct cpuidle_state *, \
struct cpuidle_state_usage *, char *);
- ssize_t (*store)(struct cpuidle_state *, const char *, size_t);
+ ssize_t (*store)(struct cpuidle_state *, \
+ struct cpuidle_state_usage *, const char *, size_t);
};
#define define_one_state_ro(_name, show) \
return sprintf(buf, "%u\n", state->_name);\
}
-#define define_store_state_function(_name) \
+#define define_store_state_ull_function(_name) \
static ssize_t store_state_##_name(struct cpuidle_state *state, \
+ struct cpuidle_state_usage *state_usage, \
const char *buf, size_t size) \
{ \
- long value; \
+ unsigned long long value; \
int err; \
if (!capable(CAP_SYS_ADMIN)) \
return -EPERM; \
- err = kstrtol(buf, 0, &value); \
+ err = kstrtoull(buf, 0, &value); \
if (err) \
return err; \
if (value) \
- state->disable = 1; \
+ state_usage->_name = 1; \
else \
- state->disable = 0; \
+ state_usage->_name = 0; \
return size; \
}
define_show_state_ull_function(time)
define_show_state_str_function(name)
define_show_state_str_function(desc)
-define_show_state_function(disable)
-define_store_state_function(disable)
+define_show_state_ull_function(disable)
+define_store_state_ull_function(disable)
define_one_state_ro(name, show_state_name);
define_one_state_ro(desc, show_state_desc);
{
int ret = -EIO;
struct cpuidle_state *state = kobj_to_state(kobj);
+ struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
if (cattr->store)
- ret = cattr->store(state, buf, size);
+ ret = cattr->store(state, state_usage, buf, size);
return ret;
}
}
-static int ux500_cryp_suspend(struct platform_device *pdev, pm_message_t state)
+static int ux500_cryp_suspend(struct device *dev)
{
int ret;
+ struct platform_device *pdev = to_platform_device(dev);
struct cryp_device_data *device_data;
struct resource *res_irq;
struct cryp_ctx *temp_ctx = NULL;
- dev_dbg(&pdev->dev, "[%s]", __func__);
+ dev_dbg(dev, "[%s]", __func__);
/* Handle state? */
device_data = platform_get_drvdata(pdev);
if (!device_data) {
- dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
- __func__);
+ dev_err(dev, "[%s]: platform_get_drvdata() failed!", __func__);
return -ENOMEM;
}
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res_irq)
- dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
- __func__);
+ dev_err(dev, "[%s]: IORESOURCE_IRQ, unavailable", __func__);
else
disable_irq(res_irq->start);
if (device_data->current_ctx == ++temp_ctx) {
if (down_interruptible(&driver_data.device_allocation))
- dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
- "failed", __func__);
- ret = cryp_disable_power(&pdev->dev, device_data, false);
+ dev_dbg(dev, "[%s]: down_interruptible() failed",
+ __func__);
+ ret = cryp_disable_power(dev, device_data, false);
} else
- ret = cryp_disable_power(&pdev->dev, device_data, true);
+ ret = cryp_disable_power(dev, device_data, true);
if (ret)
- dev_err(&pdev->dev, "[%s]: cryp_disable_power()", __func__);
+ dev_err(dev, "[%s]: cryp_disable_power()", __func__);
return ret;
}
-static int ux500_cryp_resume(struct platform_device *pdev)
+static int ux500_cryp_resume(struct device *dev)
{
int ret = 0;
+ struct platform_device *pdev = to_platform_device(dev);
struct cryp_device_data *device_data;
struct resource *res_irq;
struct cryp_ctx *temp_ctx = NULL;
- dev_dbg(&pdev->dev, "[%s]", __func__);
+ dev_dbg(dev, "[%s]", __func__);
device_data = platform_get_drvdata(pdev);
if (!device_data) {
- dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
- __func__);
+ dev_err(dev, "[%s]: platform_get_drvdata() failed!", __func__);
return -ENOMEM;
}
if (!device_data->current_ctx)
up(&driver_data.device_allocation);
else
- ret = cryp_enable_power(&pdev->dev, device_data, true);
+ ret = cryp_enable_power(dev, device_data, true);
if (ret)
- dev_err(&pdev->dev, "[%s]: cryp_enable_power() failed!",
- __func__);
+ dev_err(dev, "[%s]: cryp_enable_power() failed!", __func__);
else {
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res_irq)
return ret;
}
+static SIMPLE_DEV_PM_OPS(ux500_cryp_pm, ux500_cryp_suspend, ux500_cryp_resume);
+
static struct platform_driver cryp_driver = {
.probe = ux500_cryp_probe,
.remove = ux500_cryp_remove,
.shutdown = ux500_cryp_shutdown,
- .suspend = ux500_cryp_suspend,
- .resume = ux500_cryp_resume,
.driver = {
.owner = THIS_MODULE,
.name = "cryp1"
+ .pm = &ux500_cryp_pm,
}
};
/**
* ux500_hash_suspend - Function that suspends the hash device.
- * @pdev: The platform device.
- * @state: -
+ * @dev: Device to suspend.
*/
-static int ux500_hash_suspend(struct platform_device *pdev, pm_message_t state)
+static int ux500_hash_suspend(struct device *dev)
{
int ret;
struct hash_device_data *device_data;
struct hash_ctx *temp_ctx = NULL;
- device_data = platform_get_drvdata(pdev);
+ device_data = dev_get_drvdata(dev);
if (!device_data) {
- dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
- __func__);
+ dev_err(dev, "[%s] platform_get_drvdata() failed!", __func__);
return -ENOMEM;
}
if (device_data->current_ctx == ++temp_ctx) {
if (down_interruptible(&driver_data.device_allocation))
- dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
- "failed", __func__);
+ dev_dbg(dev, "[%s]: down_interruptible() failed",
+ __func__);
ret = hash_disable_power(device_data, false);
} else
ret = hash_disable_power(device_data, true);
if (ret)
- dev_err(&pdev->dev, "[%s]: hash_disable_power()", __func__);
+ dev_err(dev, "[%s]: hash_disable_power()", __func__);
return ret;
}
/**
* ux500_hash_resume - Function that resume the hash device.
- * @pdev: The platform device.
+ * @dev: Device to resume.
*/
-static int ux500_hash_resume(struct platform_device *pdev)
+static int ux500_hash_resume(struct device *dev)
{
int ret = 0;
struct hash_device_data *device_data;
struct hash_ctx *temp_ctx = NULL;
- device_data = platform_get_drvdata(pdev);
+ device_data = dev_get_drvdata(dev);
if (!device_data) {
- dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
- __func__);
+ dev_err(dev, "[%s] platform_get_drvdata() failed!", __func__);
return -ENOMEM;
}
ret = hash_enable_power(device_data, true);
if (ret)
- dev_err(&pdev->dev, "[%s]: hash_enable_power() failed!",
- __func__);
+ dev_err(dev, "[%s]: hash_enable_power() failed!", __func__);
return ret;
}
+static SIMPLE_DEV_PM_OPS(ux500_hash_pm, ux500_hash_suspend, ux500_hash_resume);
+
static struct platform_driver hash_driver = {
.probe = ux500_hash_probe,
.remove = ux500_hash_remove,
.shutdown = ux500_hash_shutdown,
- .suspend = ux500_hash_suspend,
- .resume = ux500_hash_resume,
.driver = {
.owner = THIS_MODULE,
.name = "hash1",
+ .pm = &ux500_hash_pm,
}
};
return 0;
}
-static int acpi_power_meter_resume(struct acpi_device *device)
+static int acpi_power_meter_resume(struct device *dev)
{
struct acpi_power_meter_resource *resource;
- if (!device || !acpi_driver_data(device))
+ if (!dev)
+ return -EINVAL;
+
+ resource = acpi_driver_data(to_acpi_device(dev));
+ if (!resource)
return -EINVAL;
- resource = acpi_driver_data(device);
free_capabilities(resource);
read_capabilities(resource);
return 0;
}
+static SIMPLE_DEV_PM_OPS(acpi_power_meter_pm, NULL, acpi_power_meter_resume);
+
static struct acpi_driver acpi_power_meter_driver = {
.name = "power_meter",
.class = ACPI_POWER_METER_CLASS,
.ops = {
.add = acpi_power_meter_add,
.remove = acpi_power_meter_remove,
- .resume = acpi_power_meter_resume,
.notify = acpi_power_meter_notify,
},
+ .drv.pm = &acpi_power_meter_pm,
};
/* Module init/exit routines */
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
static int intel_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
+static int intel_idle_cpu_init(int cpu);
static struct cpuidle_state *cpuidle_state_table;
clockevents_notify(reason, &cpu);
}
-static int setup_broadcast_cpuhp_notify(struct notifier_block *n,
- unsigned long action, void *hcpu)
+static int cpu_hotplug_notify(struct notifier_block *n,
+ unsigned long action, void *hcpu)
{
int hotcpu = (unsigned long)hcpu;
+ struct cpuidle_device *dev;
switch (action & 0xf) {
case CPU_ONLINE:
- smp_call_function_single(hotcpu, __setup_broadcast_timer,
- (void *)true, 1);
+
+ if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
+ smp_call_function_single(hotcpu, __setup_broadcast_timer,
+ (void *)true, 1);
+
+ /*
+ * Some systems can hotplug a cpu at runtime after
+ * the kernel has booted, we have to initialize the
+ * driver in this case
+ */
+ dev = per_cpu_ptr(intel_idle_cpuidle_devices, hotcpu);
+ if (!dev->registered)
+ intel_idle_cpu_init(hotcpu);
+
break;
}
return NOTIFY_OK;
}
-static struct notifier_block setup_broadcast_notifier = {
- .notifier_call = setup_broadcast_cpuhp_notify,
+static struct notifier_block cpu_hotplug_notifier = {
+ .notifier_call = cpu_hotplug_notify,
};
static void auto_demotion_disable(void *dummy)
if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */
lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE;
- else {
+ else
on_each_cpu(__setup_broadcast_timer, (void *)true, 1);
- register_cpu_notifier(&setup_broadcast_notifier);
- }
+
+ register_cpu_notifier(&cpu_hotplug_notifier);
pr_debug(PREFIX "v" INTEL_IDLE_VERSION
" model 0x%X\n", boot_cpu_data.x86_model);
* allocate, initialize, register cpuidle_devices
* @cpu: cpu/core to initialize
*/
-int intel_idle_cpu_init(int cpu)
+static int intel_idle_cpu_init(int cpu)
{
int cstate;
struct cpuidle_device *dev;
return 0;
}
-EXPORT_SYMBOL_GPL(intel_idle_cpu_init);
static int __init intel_idle_init(void)
{
intel_idle_cpuidle_devices_uninit();
cpuidle_unregister_driver(&intel_idle_driver);
- if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) {
+
+ if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
on_each_cpu(__setup_broadcast_timer, (void *)false, 1);
- unregister_cpu_notifier(&setup_broadcast_notifier);
- }
+ unregister_cpu_notifier(&cpu_hotplug_notifier);
return;
}
return 0;
}
-static int acer_platform_suspend(struct platform_device *dev,
-pm_message_t state)
+static int acer_suspend(struct device *dev)
{
u32 value;
struct acer_data *data = &interface->data;
return 0;
}
-static int acer_platform_resume(struct platform_device *device)
+static int acer_resume(struct device *dev)
{
struct acer_data *data = &interface->data;
return 0;
}
+static SIMPLE_DEV_PM_OPS(acer_pm, acer_suspend, acer_resume);
+
static void acer_platform_shutdown(struct platform_device *device)
{
struct acer_data *data = &interface->data;
.driver = {
.name = "acer-wmi",
.owner = THIS_MODULE,
+ .pm = &acer_pm,
},
.probe = acer_platform_probe,
.remove = acer_platform_remove,
- .suspend = acer_platform_suspend,
- .resume = acer_platform_resume,
.shutdown = acer_platform_shutdown,
};
return cmpc_remove_acpi_notify_device(acpi);
}
-static int cmpc_tablet_resume(struct acpi_device *acpi)
+static int cmpc_tablet_resume(struct device *dev)
{
- struct input_dev *inputdev = dev_get_drvdata(&acpi->dev);
+ struct input_dev *inputdev = dev_get_drvdata(dev);
+
unsigned long long val = 0;
- if (ACPI_SUCCESS(cmpc_get_tablet(acpi->handle, &val)))
+ if (ACPI_SUCCESS(cmpc_get_tablet(to_acpi_device(dev)->handle, &val)))
input_report_switch(inputdev, SW_TABLET_MODE, !val);
return 0;
}
+static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
+
static const struct acpi_device_id cmpc_tablet_device_ids[] = {
{CMPC_TABLET_HID, 0},
{"", 0}
.ops = {
.add = cmpc_tablet_add,
.remove = cmpc_tablet_remove,
- .resume = cmpc_tablet_resume,
.notify = cmpc_tablet_handler,
- }
+ },
+ .drv.pm = &cmpc_tablet_pm,
};
return 0;
}
-static int acpi_fujitsu_resume(struct acpi_device *adev)
+static int acpi_fujitsu_resume(struct device *dev)
{
fujitsu_reset();
return 0;
}
+static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume);
+
static struct acpi_driver acpi_fujitsu_driver = {
.name = MODULENAME,
.class = "hotkey",
.ops = {
.add = acpi_fujitsu_add,
.remove = acpi_fujitsu_remove,
- .resume = acpi_fujitsu_resume,
- }
+ },
+ .drv.pm = &acpi_fujitsu_pm,
};
static int __init fujitsu_module_init(void)
return 0;
}
-static int hdaps_resume(struct platform_device *dev)
+static int hdaps_resume(struct device *dev)
{
return hdaps_device_init();
}
+static SIMPLE_DEV_PM_OPS(hdaps_pm, NULL, hdaps_resume);
+
static struct platform_driver hdaps_driver = {
.probe = hdaps_probe,
- .resume = hdaps_resume,
.driver = {
.name = "hdaps",
.owner = THIS_MODULE,
+ .pm = &hdaps_pm,
},
};
#ifdef CONFIG_PM
-static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
+static int lis3lv02d_suspend(struct device *dev)
{
/* make sure the device is off when we suspend */
lis3lv02d_poweroff(&lis3_dev);
return 0;
}
-static int lis3lv02d_resume(struct acpi_device *device)
+static int lis3lv02d_resume(struct device *dev)
{
return lis3lv02d_poweron(&lis3_dev);
}
+
+static SIMPLE_DEV_PM_OPS(hp_accel_pm, lis3lv02d_suspend, lis3lv02d_resume);
+#define HP_ACCEL_PM (&hp_accel_pm)
#else
-#define lis3lv02d_suspend NULL
-#define lis3lv02d_resume NULL
+#define HP_ACCEL_PM NULL
#endif
/* For the HP MDPS aka 3D Driveguard */
.ops = {
.add = lis3lv02d_add,
.remove = lis3lv02d_remove,
- .suspend = lis3lv02d_suspend,
- .resume = lis3lv02d_resume,
- }
+ },
+ .drv.pm = HP_ACCEL_PM,
};
static int __init lis3lv02d_init_module(void)
dev_dbg(&dev->dev, "IPS driver removed\n");
}
-#ifdef CONFIG_PM
-static int ips_suspend(struct pci_dev *dev, pm_message_t state)
-{
- return 0;
-}
-
-static int ips_resume(struct pci_dev *dev)
-{
- return 0;
-}
-#else
-#define ips_suspend NULL
-#define ips_resume NULL
-#endif /* CONFIG_PM */
-
static void ips_shutdown(struct pci_dev *dev)
{
}
.id_table = ips_id_table,
.probe = ips_probe,
.remove = ips_remove,
- .suspend = ips_suspend,
- .resume = ips_resume,
.shutdown = ips_shutdown,
};
/**
* mid_thermal_resume - resume routine
- * @pdev: platform device structure
+ * @dev: device structure
*
* mid thermal resume: re-initializes the adc. Can sleep.
*/
-static int mid_thermal_resume(struct platform_device *pdev)
+static int mid_thermal_resume(struct device *dev)
{
- return mid_initialize_adc(&pdev->dev);
+ return mid_initialize_adc(dev);
}
/**
* mid_thermal_suspend - suspend routine
- * @pdev: platform device structure
+ * @dev: device structure
*
* mid thermal suspend implements the suspend functionality
* by stopping the ADC. Can sleep.
*/
-static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg)
+static int mid_thermal_suspend(struct device *dev)
{
/*
* This just stops the ADC and does not disable it.
return configure_adc(0);
}
+static SIMPLE_DEV_PM_OPS(mid_thermal_pm,
+ mid_thermal_suspend, mid_thermal_resume);
+
/**
* read_curr_temp - reads the current temperature and stores in temp
* @temp: holds the current temperature value after reading
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
+ .pm = &mid_thermal_pm,
},
.probe = mid_thermal_probe,
- .suspend = mid_thermal_suspend,
- .resume = mid_thermal_resume,
.remove = __devexit_p(mid_thermal_remove),
.id_table = therm_id_table,
};
#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4
#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
-static int msi_laptop_resume(struct platform_device *device);
+static int msi_laptop_resume(struct device *device);
+static SIMPLE_DEV_PM_OPS(msi_laptop_pm, NULL, msi_laptop_resume);
#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
.driver = {
.name = "msi-laptop-pf",
.owner = THIS_MODULE,
+ .pm = &msi_laptop_pm,
},
- .resume = msi_laptop_resume,
};
static struct platform_device *msipf_device;
return retval;
}
-static int msi_laptop_resume(struct platform_device *device)
+static int msi_laptop_resume(struct device *device)
{
u8 data;
int result;
static int acpi_pcc_hotkey_add(struct acpi_device *device);
static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type);
-static int acpi_pcc_hotkey_resume(struct acpi_device *device);
static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id pcc_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, pcc_device_ids);
+static int acpi_pcc_hotkey_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume);
+
static struct acpi_driver acpi_pcc_driver = {
.name = ACPI_PCC_DRIVER_NAME,
.class = ACPI_PCC_CLASS,
.ops = {
.add = acpi_pcc_hotkey_add,
.remove = acpi_pcc_hotkey_remove,
- .resume = acpi_pcc_hotkey_resume,
.notify = acpi_pcc_hotkey_notify,
},
+ .drv.pm = &acpi_pcc_hotkey_pm,
};
static const struct key_entry panasonic_keymap[] = {
/* kernel module interface */
-static int acpi_pcc_hotkey_resume(struct acpi_device *device)
+static int acpi_pcc_hotkey_resume(struct device *dev)
{
- struct pcc_acpi *pcc = acpi_driver_data(device);
+ struct pcc_acpi *pcc;
+
+ if (!dev)
+ return -EINVAL;
- if (device == NULL || pcc == NULL)
+ pcc = acpi_driver_data(to_acpi_device(dev));
+ if (!pcc)
return -EINVAL;
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n",
&result);
}
-static int sony_nc_resume(struct acpi_device *device)
+static int sony_nc_resume(struct device *dev)
{
struct sony_nc_value *item;
acpi_handle handle;
return 0;
}
+static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume);
+
static void sony_nc_rfkill_cleanup(void)
{
int i;
.ops = {
.add = sony_nc_add,
.remove = sony_nc_remove,
- .resume = sony_nc_resume,
.notify = sony_nc_notify,
},
+ .drv.pm = &sony_nc_pm,
};
/*********** SPIC (SNY6001) Device ***********/
return result;
}
-static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
+static int sony_pic_suspend(struct device *dev)
{
- if (sony_pic_disable(device))
+ if (sony_pic_disable(to_acpi_device(dev)))
return -ENXIO;
return 0;
}
-static int sony_pic_resume(struct acpi_device *device)
+static int sony_pic_resume(struct device *dev)
{
- sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+ sony_pic_enable(to_acpi_device(dev),
+ spic_dev.cur_ioport, spic_dev.cur_irq);
return 0;
}
+static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
+
static const struct acpi_device_id sony_pic_device_ids[] = {
{SONY_PIC_HID, 0},
{"", 0},
.ops = {
.add = sony_pic_add,
.remove = sony_pic_remove,
- .suspend = sony_pic_suspend,
- .resume = sony_pic_resume,
},
+ .drv.pm = &sony_pic_pm,
};
static struct dmi_system_id __initdata sonypi_dmi_table[] = {
int (*write) (char *);
void (*exit) (void);
void (*resume) (void);
- void (*suspend) (pm_message_t state);
+ void (*suspend) (void);
void (*shutdown) (void);
struct list_head all_drivers;
static struct mutex tpacpi_inputdev_send_mutex;
static LIST_HEAD(tpacpi_all_drivers);
-static int tpacpi_suspend_handler(struct platform_device *pdev,
- pm_message_t state)
+static int tpacpi_suspend_handler(struct device *dev)
{
struct ibm_struct *ibm, *itmp;
&tpacpi_all_drivers,
all_drivers) {
if (ibm->suspend)
- (ibm->suspend)(state);
+ (ibm->suspend)();
}
return 0;
}
-static int tpacpi_resume_handler(struct platform_device *pdev)
+static int tpacpi_resume_handler(struct device *dev)
{
struct ibm_struct *ibm, *itmp;
return 0;
}
+static SIMPLE_DEV_PM_OPS(tpacpi_pm,
+ tpacpi_suspend_handler, tpacpi_resume_handler);
+
static void tpacpi_shutdown_handler(struct platform_device *pdev)
{
struct ibm_struct *ibm, *itmp;
.driver = {
.name = TPACPI_DRVR_NAME,
.owner = THIS_MODULE,
+ .pm = &tpacpi_pm,
},
- .suspend = tpacpi_suspend_handler,
- .resume = tpacpi_resume_handler,
.shutdown = tpacpi_shutdown_handler,
};
}
}
-static void hotkey_suspend(pm_message_t state)
+static void hotkey_suspend(void)
{
/* Do these on suspend, we get the events on early resume! */
hotkey_wakeup_reason = TP_ACPI_WAKEUP_NONE;
return 0;
}
-static void brightness_suspend(pm_message_t state)
+static void brightness_suspend(void)
{
tpacpi_brightness_checkpoint_nvram();
}
.get = volume_alsa_mute_get,
};
-static void volume_suspend(pm_message_t state)
+static void volume_suspend(void)
{
tpacpi_volume_checkpoint_nvram();
}
flush_workqueue(tpacpi_wq);
}
-static void fan_suspend(pm_message_t state)
+static void fan_suspend(void)
{
int rc;
}
}
-static int toshiba_acpi_suspend(struct acpi_device *acpi_dev,
- pm_message_t state)
+static int toshiba_acpi_suspend(struct device *device)
{
- struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+ struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
u32 result;
if (dev->hotkey_dev)
return 0;
}
-static int toshiba_acpi_resume(struct acpi_device *acpi_dev)
+static int toshiba_acpi_resume(struct device *device)
{
- struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
+ struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
u32 result;
if (dev->hotkey_dev)
return 0;
}
+static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
+ toshiba_acpi_suspend, toshiba_acpi_resume);
+
static struct acpi_driver toshiba_acpi_driver = {
.name = "Toshiba ACPI driver",
.owner = THIS_MODULE,
.add = toshiba_acpi_add,
.remove = toshiba_acpi_remove,
.notify = toshiba_acpi_notify,
- .suspend = toshiba_acpi_suspend,
- .resume = toshiba_acpi_resume,
},
+ .drv.pm = &toshiba_acpi_pm,
};
static int __init toshiba_acpi_init(void)
static int toshiba_bt_rfkill_add(struct acpi_device *device);
static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type);
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
-static int toshiba_bt_resume(struct acpi_device *device);
static const struct acpi_device_id bt_device_ids[] = {
{ "TOS6205", 0},
};
MODULE_DEVICE_TABLE(acpi, bt_device_ids);
+static int toshiba_bt_resume(struct device *dev);
+static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume);
+
static struct acpi_driver toshiba_bt_rfkill_driver = {
.name = "Toshiba BT",
.class = "Toshiba",
.add = toshiba_bt_rfkill_add,
.remove = toshiba_bt_rfkill_remove,
.notify = toshiba_bt_rfkill_notify,
- .resume = toshiba_bt_resume,
},
.owner = THIS_MODULE,
+ .drv.pm = &toshiba_bt_pm,
};
toshiba_bluetooth_enable(device->handle);
}
-static int toshiba_bt_resume(struct acpi_device *device)
+static int toshiba_bt_resume(struct device *dev)
{
- return toshiba_bluetooth_enable(device->handle);
+ return toshiba_bluetooth_enable(to_acpi_device(dev)->handle);
}
static int toshiba_bt_rfkill_add(struct acpi_device *device)
}
}
-static int ebook_switch_resume(struct acpi_device *device)
+static int ebook_switch_resume(struct device *dev)
{
- return ebook_send_state(device);
+ return ebook_send_state(to_acpi_device(dev));
}
+static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume);
+
static int ebook_switch_add(struct acpi_device *device)
{
struct ebook_switch *button;
.ids = ebook_device_ids,
.ops = {
.add = ebook_switch_add,
- .resume = ebook_switch_resume,
.remove = ebook_switch_remove,
.notify = ebook_switch_notify,
},
+ .drv.pm = &ebook_switch_pm,
};
static int __init xo15_ebook_init(void)
hpet_mask_rtc_irq_bit(RTC_AIE);
CMOS_READ(RTC_INTR_FLAGS);
+ pm_wakeup_event(cmos_rtc.dev, 0);
}
spin_unlock(&rtc_lock);
typedef int (*acpi_op_add) (struct acpi_device * device);
typedef int (*acpi_op_remove) (struct acpi_device * device, int type);
typedef int (*acpi_op_start) (struct acpi_device * device);
-typedef int (*acpi_op_suspend) (struct acpi_device * device,
- pm_message_t state);
-typedef int (*acpi_op_resume) (struct acpi_device * device);
typedef int (*acpi_op_bind) (struct acpi_device * device);
typedef int (*acpi_op_unbind) (struct acpi_device * device);
typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event);
acpi_op_add add;
acpi_op_remove remove;
acpi_op_start start;
- acpi_op_suspend suspend;
- acpi_op_resume resume;
acpi_op_bind bind;
acpi_op_unbind unbind;
acpi_op_notify notify;
u8 entry_method;
u8 index;
u32 latency;
- u32 latency_ticks;
u32 power;
- u32 usage;
- u64 time;
u8 bm_sts_skip;
char desc[ACPI_CX_DESC_LEN];
};
int acpi_processor_hotplug(struct acpi_processor *pr);
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device);
-int acpi_processor_suspend(struct acpi_device * device, pm_message_t state);
-int acpi_processor_resume(struct acpi_device * device);
+int acpi_processor_suspend(struct device *dev);
+int acpi_processor_resume(struct device *dev);
extern struct cpuidle_driver acpi_idle_driver;
/* in processor_thermal.c */
struct cpuidle_state_usage {
void *driver_data;
+ unsigned long long disable;
unsigned long long usage;
unsigned long long time; /* in US */
};
unsigned int exit_latency; /* in US */
int power_usage; /* in mW */
unsigned int target_residency; /* in US */
- unsigned int disable;
+ bool disabled; /* disabled on all CPUs */
int (*enter) (struct cpuidle_device *dev,
struct cpuidle_driver *drv,
extern void disable_cpuidle(void);
extern int cpuidle_idle_call(void);
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
-struct cpuidle_driver *cpuidle_get_driver(void);
+extern struct cpuidle_driver *cpuidle_get_driver(void);
+extern struct cpuidle_driver *cpuidle_driver_ref(void);
+extern void cpuidle_driver_unref(void);
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
extern int cpuidle_register_device(struct cpuidle_device *dev);
extern void cpuidle_unregister_device(struct cpuidle_device *dev);
extern void cpuidle_pause_and_lock(void);
extern void cpuidle_resume_and_unlock(void);
+extern void cpuidle_pause(void);
+extern void cpuidle_resume(void);
extern int cpuidle_enable_device(struct cpuidle_device *dev);
extern void cpuidle_disable_device(struct cpuidle_device *dev);
extern int cpuidle_wrap_enter(struct cpuidle_device *dev,
static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
{return -ENODEV; }
static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
+static inline struct cpuidle_driver *cpuidle_driver_ref(void) {return NULL; }
+static inline void cpuidle_driver_unref(void) {}
static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
static inline int cpuidle_register_device(struct cpuidle_device *dev)
{return -ENODEV; }
static inline void cpuidle_pause_and_lock(void) { }
static inline void cpuidle_resume_and_unlock(void) { }
+static inline void cpuidle_pause(void) { }
+static inline void cpuidle_resume(void) { }
static inline int cpuidle_enable_device(struct cpuidle_device *dev)
{return -ENODEV; }
static inline void cpuidle_disable_device(struct cpuidle_device *dev) { }
extern int cpuidle_register_governor(struct cpuidle_governor *gov);
extern void cpuidle_unregister_governor(struct cpuidle_governor *gov);
-#ifdef CONFIG_INTEL_IDLE
-extern int intel_idle_cpu_init(int cpu);
#else
-static inline int intel_idle_cpu_init(int cpu) { return -1; }
-#endif
-
-#else
-static inline int intel_idle_cpu_init(int cpu) { return -1; }
static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
{return 0;}
#include <linux/err.h>
#include <linux/of.h>
#include <linux/notifier.h>
+#include <linux/cpuidle.h>
enum gpd_status {
GPD_STATE_ACTIVE = 0, /* PM domain is active */
bool (*active_wakeup)(struct device *dev);
};
+struct gpd_cpu_data {
+ unsigned int saved_exit_latency;
+ struct cpuidle_state *idle_state;
+};
+
struct generic_pm_domain {
struct dev_pm_domain domain; /* PM domain operations */
struct list_head gpd_list_node; /* Node in the global PM domains list */
bool max_off_time_changed;
bool cached_power_down_ok;
struct device_node *of_node; /* Node in device tree */
+ struct gpd_cpu_data *cpu_data;
};
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
struct gpd_timing_data td;
struct notifier_block nb;
struct mutex lock;
+ unsigned int refcount;
bool need_restore;
bool always_on;
};
struct gpd_dev_ops *ops,
struct gpd_timing_data *td);
extern int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td);
+extern int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state);
+extern int genpd_detach_cpuidle(struct generic_pm_domain *genpd);
extern void pm_genpd_init(struct generic_pm_domain *genpd,
struct dev_power_governor *gov, bool is_off);
{
return -ENOSYS;
}
+static inline int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int st)
+{
+ return -ENOSYS;
+}
+static inline int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+{
+ return -ENOSYS;
+}
static inline void pm_genpd_init(struct generic_pm_domain *genpd,
struct dev_power_governor *gov, bool is_off)
{
static inline int dev_pm_qos_request_active(struct dev_pm_qos_request *req)
{
- return req->dev != 0;
+ return req->dev != NULL;
}
int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node,