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