blob: 4af7c1cbf909b61d576bc0900df85983d2eedf9d [file] [log] [blame]
Rafael J. Wysockief27bed12011-08-25 15:34:01 +02001/*
2 * drivers/base/power/common.c - Common device power management code.
3 *
4 * Copyright (C) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
5 *
6 * This file is released under the GPLv2.
7 */
8
9#include <linux/init.h>
10#include <linux/kernel.h>
Paul Gortmakeraaf19542011-09-28 18:23:03 -040011#include <linux/export.h>
Rafael J. Wysockief27bed12011-08-25 15:34:01 +020012#include <linux/slab.h>
Rafael J. Wysockib5e8d262011-08-25 15:34:19 +020013#include <linux/pm_clock.h>
Rafael J. Wysockief27bed12011-08-25 15:34:01 +020014
15/**
16 * dev_pm_get_subsys_data - Create or refcount power.subsys_data for device.
17 * @dev: Device to handle.
18 *
19 * If power.subsys_data is NULL, point it to a new object, otherwise increment
20 * its reference counter. Return 1 if a new object has been created, otherwise
21 * return 0 or error code.
22 */
23int dev_pm_get_subsys_data(struct device *dev)
24{
25 struct pm_subsys_data *psd;
26 int ret = 0;
27
28 psd = kzalloc(sizeof(*psd), GFP_KERNEL);
29 if (!psd)
30 return -ENOMEM;
31
32 spin_lock_irq(&dev->power.lock);
33
34 if (dev->power.subsys_data) {
35 dev->power.subsys_data->refcount++;
36 } else {
37 spin_lock_init(&psd->lock);
38 psd->refcount = 1;
39 dev->power.subsys_data = psd;
40 pm_clk_init(dev);
41 psd = NULL;
42 ret = 1;
43 }
44
45 spin_unlock_irq(&dev->power.lock);
46
47 /* kfree() verifies that its argument is nonzero. */
48 kfree(psd);
49
50 return ret;
51}
52EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
53
54/**
55 * dev_pm_put_subsys_data - Drop reference to power.subsys_data.
56 * @dev: Device to handle.
57 *
58 * If the reference counter of power.subsys_data is zero after dropping the
59 * reference, power.subsys_data is removed. Return 1 if that happens or 0
60 * otherwise.
61 */
62int dev_pm_put_subsys_data(struct device *dev)
63{
64 struct pm_subsys_data *psd;
65 int ret = 0;
66
67 spin_lock_irq(&dev->power.lock);
68
69 psd = dev_to_psd(dev);
70 if (!psd) {
71 ret = -EINVAL;
72 goto out;
73 }
74
75 if (--psd->refcount == 0) {
76 dev->power.subsys_data = NULL;
77 kfree(psd);
78 ret = 1;
79 }
80
81 out:
82 spin_unlock_irq(&dev->power.lock);
83
84 return ret;
85}
86EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data);