• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/mach-shmobile/
1/*
2 * arch/arm/mach-shmobile/pm_runtime.c
3 *
4 * Runtime PM support code for SuperH Mobile ARM
5 *
6 *  Copyright (C) 2009-2010 Magnus Damm
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License.  See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/io.h>
16#include <linux/pm_runtime.h>
17#include <linux/platform_device.h>
18#include <linux/clk.h>
19#include <linux/sh_clk.h>
20#include <linux/bitmap.h>
21
22#ifdef CONFIG_PM_RUNTIME
23#define BIT_ONCE 0
24#define BIT_ACTIVE 1
25#define BIT_CLK_ENABLED 2
26
27struct pm_runtime_data {
28	unsigned long flags;
29	struct clk *clk;
30};
31
32static void __devres_release(struct device *dev, void *res)
33{
34	struct pm_runtime_data *prd = res;
35
36	dev_dbg(dev, "__devres_release()\n");
37
38	if (test_bit(BIT_CLK_ENABLED, &prd->flags))
39		clk_disable(prd->clk);
40
41	if (test_bit(BIT_ACTIVE, &prd->flags))
42		clk_put(prd->clk);
43}
44
45static struct pm_runtime_data *__to_prd(struct device *dev)
46{
47	return devres_find(dev, __devres_release, NULL, NULL);
48}
49
50static void platform_pm_runtime_init(struct device *dev,
51				     struct pm_runtime_data *prd)
52{
53	if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) {
54		prd->clk = clk_get(dev, NULL);
55		if (!IS_ERR(prd->clk)) {
56			set_bit(BIT_ACTIVE, &prd->flags);
57			dev_info(dev, "clocks managed by runtime pm\n");
58		}
59	}
60}
61
62static void platform_pm_runtime_bug(struct device *dev,
63				    struct pm_runtime_data *prd)
64{
65	if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags))
66		dev_err(dev, "runtime pm suspend before resume\n");
67}
68
69int platform_pm_runtime_suspend(struct device *dev)
70{
71	struct pm_runtime_data *prd = __to_prd(dev);
72
73	dev_dbg(dev, "platform_pm_runtime_suspend()\n");
74
75	platform_pm_runtime_bug(dev, prd);
76
77	if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
78		clk_disable(prd->clk);
79		clear_bit(BIT_CLK_ENABLED, &prd->flags);
80	}
81
82	return 0;
83}
84
85int platform_pm_runtime_resume(struct device *dev)
86{
87	struct pm_runtime_data *prd = __to_prd(dev);
88
89	dev_dbg(dev, "platform_pm_runtime_resume()\n");
90
91	platform_pm_runtime_init(dev, prd);
92
93	if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
94		clk_enable(prd->clk);
95		set_bit(BIT_CLK_ENABLED, &prd->flags);
96	}
97
98	return 0;
99}
100
101int platform_pm_runtime_idle(struct device *dev)
102{
103	/* suspend synchronously to disable clocks immediately */
104	return pm_runtime_suspend(dev);
105}
106
107static int platform_bus_notify(struct notifier_block *nb,
108			       unsigned long action, void *data)
109{
110	struct device *dev = data;
111	struct pm_runtime_data *prd;
112
113	dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
114
115	if (action == BUS_NOTIFY_BIND_DRIVER) {
116		prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL);
117		if (prd)
118			devres_add(dev, prd);
119		else
120			dev_err(dev, "unable to alloc memory for runtime pm\n");
121	}
122
123	return 0;
124}
125
126#else /* CONFIG_PM_RUNTIME */
127
128static int platform_bus_notify(struct notifier_block *nb,
129			       unsigned long action, void *data)
130{
131	struct device *dev = data;
132	struct clk *clk;
133
134	dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
135
136	switch (action) {
137	case BUS_NOTIFY_BIND_DRIVER:
138		clk = clk_get(dev, NULL);
139		if (!IS_ERR(clk)) {
140			clk_enable(clk);
141			clk_put(clk);
142			dev_info(dev, "runtime pm disabled, clock forced on\n");
143		}
144		break;
145	case BUS_NOTIFY_UNBOUND_DRIVER:
146		clk = clk_get(dev, NULL);
147		if (!IS_ERR(clk)) {
148			clk_disable(clk);
149			clk_put(clk);
150			dev_info(dev, "runtime pm disabled, clock forced off\n");
151		}
152		break;
153	}
154
155	return 0;
156}
157
158#endif /* CONFIG_PM_RUNTIME */
159
160static struct notifier_block platform_bus_notifier = {
161	.notifier_call = platform_bus_notify
162};
163
164static int __init sh_pm_runtime_init(void)
165{
166	bus_register_notifier(&platform_bus_type, &platform_bus_notifier);
167	return 0;
168}
169core_initcall(sh_pm_runtime_init);
170