blob: f061eaa48bb517172553be215e72fe0f242be139 [file] [log] [blame]
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +02001/*
2 * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks
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
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +02009#include <linux/kernel.h>
Paul Gortmaker51990e82012-01-22 11:23:42 -050010#include <linux/device.h>
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020011#include <linux/io.h>
12#include <linux/pm.h>
Rafael J. Wysockib5e8d262011-08-25 15:34:19 +020013#include <linux/pm_clock.h>
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020014#include <linux/clk.h>
Geert Uytterhoeven245bd6f2014-11-06 15:51:00 +020015#include <linux/clkdev.h>
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020016#include <linux/slab.h>
17#include <linux/err.h>
18
Rafael J. Wysockib7b95922011-07-01 22:13:37 +020019#ifdef CONFIG_PM
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020020
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020021enum pce_status {
22 PCE_STATUS_NONE = 0,
23 PCE_STATUS_ACQUIRED,
24 PCE_STATUS_ENABLED,
25 PCE_STATUS_ERROR,
26};
27
28struct pm_clock_entry {
29 struct list_head node;
30 char *con_id;
31 struct clk *clk;
32 enum pce_status status;
33};
34
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020035/**
Ben Dooks5cda3fb2014-01-14 12:23:42 +000036 * pm_clk_enable - Enable a clock, reporting any errors
37 * @dev: The device for the given clock
38 * @clk: The clock being enabled.
39 */
40static inline int __pm_clk_enable(struct device *dev, struct clk *clk)
41{
42 int ret = clk_enable(clk);
43 if (ret)
44 dev_err(dev, "%s: failed to enable clk %p, error %d\n",
45 __func__, clk, ret);
46
47 return ret;
48}
49
50/**
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +020051 * pm_clk_acquire - Acquire a device clock.
52 * @dev: Device whose clock is to be acquired.
53 * @ce: PM clock entry corresponding to the clock.
54 */
55static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
56{
Geert Uytterhoeven245bd6f2014-11-06 15:51:00 +020057 if (!ce->clk)
58 ce->clk = clk_get(dev, ce->con_id);
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +020059 if (IS_ERR(ce->clk)) {
60 ce->status = PCE_STATUS_ERROR;
61 } else {
Ben Dooks8a6720e2014-01-14 12:23:40 +000062 clk_prepare(ce->clk);
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +020063 ce->status = PCE_STATUS_ACQUIRED;
64 dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
65 }
66}
67
Geert Uytterhoeven245bd6f2014-11-06 15:51:00 +020068static int __pm_clk_add(struct device *dev, const char *con_id,
69 struct clk *clk)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020070{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +020071 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020072 struct pm_clock_entry *ce;
73
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +020074 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020075 return -EINVAL;
76
77 ce = kzalloc(sizeof(*ce), GFP_KERNEL);
78 if (!ce) {
79 dev_err(dev, "Not enough memory for clock entry.\n");
80 return -ENOMEM;
81 }
82
83 if (con_id) {
84 ce->con_id = kstrdup(con_id, GFP_KERNEL);
85 if (!ce->con_id) {
86 dev_err(dev,
87 "Not enough memory for clock connection ID.\n");
88 kfree(ce);
89 return -ENOMEM;
90 }
Geert Uytterhoeven245bd6f2014-11-06 15:51:00 +020091 } else {
92 if (IS_ERR(ce->clk) || !__clk_get(clk)) {
93 kfree(ce);
94 return -ENOENT;
95 }
96 ce->clk = clk;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +020097 }
98
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +020099 pm_clk_acquire(dev, ce);
100
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200101 spin_lock_irq(&psd->lock);
102 list_add_tail(&ce->node, &psd->clock_list);
103 spin_unlock_irq(&psd->lock);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200104 return 0;
105}
106
107/**
Geert Uytterhoeven245bd6f2014-11-06 15:51:00 +0200108 * pm_clk_add - Start using a device clock for power management.
109 * @dev: Device whose clock is going to be used for power management.
110 * @con_id: Connection ID of the clock.
111 *
112 * Add the clock represented by @con_id to the list of clocks used for
113 * the power management of @dev.
114 */
115int pm_clk_add(struct device *dev, const char *con_id)
116{
117 return __pm_clk_add(dev, con_id, NULL);
118}
119
120/**
121 * pm_clk_add_clk - Start using a device clock for power management.
122 * @dev: Device whose clock is going to be used for power management.
123 * @clk: Clock pointer
124 *
125 * Add the clock to the list of clocks used for the power management of @dev.
126 * It will increment refcount on clock pointer, use clk_put() on it when done.
127 */
128int pm_clk_add_clk(struct device *dev, struct clk *clk)
129{
130 return __pm_clk_add(dev, NULL, clk);
131}
132
133/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200134 * __pm_clk_remove - Destroy PM clock entry.
135 * @ce: PM clock entry to destroy.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200136 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200137static void __pm_clk_remove(struct pm_clock_entry *ce)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200138{
139 if (!ce)
140 return;
141
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200142 if (ce->status < PCE_STATUS_ERROR) {
143 if (ce->status == PCE_STATUS_ENABLED)
Ben Dooks8a6720e2014-01-14 12:23:40 +0000144 clk_disable(ce->clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200145
Ben Dooks8a6720e2014-01-14 12:23:40 +0000146 if (ce->status >= PCE_STATUS_ACQUIRED) {
147 clk_unprepare(ce->clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200148 clk_put(ce->clk);
Ben Dooks8a6720e2014-01-14 12:23:40 +0000149 }
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200150 }
151
Jonghwan Choi0ab1e792011-10-22 00:22:54 +0200152 kfree(ce->con_id);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200153 kfree(ce);
154}
155
156/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200157 * pm_clk_remove - Stop using a device clock for power management.
158 * @dev: Device whose clock should not be used for PM any more.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200159 * @con_id: Connection ID of the clock.
160 *
161 * Remove the clock represented by @con_id from the list of clocks used for
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200162 * the power management of @dev.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200163 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200164void pm_clk_remove(struct device *dev, const char *con_id)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200165{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200166 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200167 struct pm_clock_entry *ce;
168
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200169 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200170 return;
171
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200172 spin_lock_irq(&psd->lock);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200173
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200174 list_for_each_entry(ce, &psd->clock_list, node) {
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200175 if (!con_id && !ce->con_id)
176 goto remove;
177 else if (!con_id || !ce->con_id)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200178 continue;
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200179 else if (!strcmp(con_id, ce->con_id))
180 goto remove;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200181 }
182
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200183 spin_unlock_irq(&psd->lock);
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200184 return;
185
186 remove:
187 list_del(&ce->node);
Rafael J. Wysocki0d41da22011-09-26 20:12:45 +0200188 spin_unlock_irq(&psd->lock);
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200189
190 __pm_clk_remove(ce);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200191}
192
193/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200194 * pm_clk_init - Initialize a device's list of power management clocks.
195 * @dev: Device to initialize the list of PM clocks for.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200196 *
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200197 * Initialize the lock and clock_list members of the device's pm_subsys_data
198 * object.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200199 */
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200200void pm_clk_init(struct device *dev)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200201{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200202 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysockief27bed12011-08-25 15:34:01 +0200203 if (psd)
204 INIT_LIST_HEAD(&psd->clock_list);
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200205}
206
207/**
208 * pm_clk_create - Create and initialize a device's list of PM clocks.
209 * @dev: Device to create and initialize the list of PM clocks for.
210 *
211 * Allocate a struct pm_subsys_data object, initialize its lock and clock_list
212 * members and make the @dev's power.subsys_data field point to it.
213 */
214int pm_clk_create(struct device *dev)
215{
Rafael J. Wysocki77254952012-08-07 13:50:14 +0200216 return dev_pm_get_subsys_data(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200217}
218
219/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200220 * pm_clk_destroy - Destroy a device's list of power management clocks.
221 * @dev: Device to destroy the list of PM clocks for.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200222 *
223 * Clear the @dev's power.subsys_data field, remove the list of clock entries
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200224 * from the struct pm_subsys_data object pointed to by it before and free
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200225 * that object.
226 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200227void pm_clk_destroy(struct device *dev)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200228{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200229 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200230 struct pm_clock_entry *ce, *c;
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200231 struct list_head list;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200232
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200233 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200234 return;
235
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200236 INIT_LIST_HEAD(&list);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200237
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200238 spin_lock_irq(&psd->lock);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200239
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200240 list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200241 list_move(&ce->node, &list);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200242
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200243 spin_unlock_irq(&psd->lock);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200244
Rafael J. Wysockief27bed12011-08-25 15:34:01 +0200245 dev_pm_put_subsys_data(dev);
Rafael J. Wysockie8b364b2011-09-26 19:40:23 +0200246
247 list_for_each_entry_safe_reverse(ce, c, &list, node) {
248 list_del(&ce->node);
249 __pm_clk_remove(ce);
250 }
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200251}
252
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200253#endif /* CONFIG_PM */
254
255#ifdef CONFIG_PM_RUNTIME
256
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200257/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200258 * pm_clk_suspend - Disable clocks in a device's PM clock list.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200259 * @dev: Device to disable the clocks for.
260 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200261int pm_clk_suspend(struct device *dev)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200262{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200263 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200264 struct pm_clock_entry *ce;
Rafael J. Wysockib7ab83e2011-08-24 21:40:56 +0200265 unsigned long flags;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200266
267 dev_dbg(dev, "%s()\n", __func__);
268
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200269 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200270 return 0;
271
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200272 spin_lock_irqsave(&psd->lock, flags);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200273
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200274 list_for_each_entry_reverse(ce, &psd->clock_list, node) {
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200275 if (ce->status < PCE_STATUS_ERROR) {
Magnus Damm24050952011-11-10 00:44:10 +0100276 if (ce->status == PCE_STATUS_ENABLED)
277 clk_disable(ce->clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200278 ce->status = PCE_STATUS_ACQUIRED;
279 }
280 }
281
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200282 spin_unlock_irqrestore(&psd->lock, flags);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200283
284 return 0;
285}
286
287/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200288 * pm_clk_resume - Enable clocks in a device's PM clock list.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200289 * @dev: Device to enable the clocks for.
290 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200291int pm_clk_resume(struct device *dev)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200292{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200293 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200294 struct pm_clock_entry *ce;
Rafael J. Wysockib7ab83e2011-08-24 21:40:56 +0200295 unsigned long flags;
Ben Dooksafdd3ab2014-01-14 12:23:41 +0000296 int ret;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200297
298 dev_dbg(dev, "%s()\n", __func__);
299
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200300 if (!psd)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200301 return 0;
302
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200303 spin_lock_irqsave(&psd->lock, flags);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200304
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200305 list_for_each_entry(ce, &psd->clock_list, node) {
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200306 if (ce->status < PCE_STATUS_ERROR) {
Ben Dooks5cda3fb2014-01-14 12:23:42 +0000307 ret = __pm_clk_enable(dev, ce->clk);
Ben Dooksafdd3ab2014-01-14 12:23:41 +0000308 if (!ret)
309 ce->status = PCE_STATUS_ENABLED;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200310 }
311 }
312
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200313 spin_unlock_irqrestore(&psd->lock, flags);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200314
315 return 0;
316}
317
318/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200319 * pm_clk_notify - Notify routine for device addition and removal.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200320 * @nb: Notifier block object this function is a member of.
321 * @action: Operation being carried out by the caller.
322 * @data: Device the routine is being run for.
323 *
324 * For this function to work, @nb must be a member of an object of type
325 * struct pm_clk_notifier_block containing all of the requisite data.
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200326 * Specifically, the pm_domain member of that object is copied to the device's
327 * pm_domain field and its con_ids member is used to populate the device's list
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200328 * of PM clocks, depending on @action.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200329 *
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200330 * If the device's pm_domain field is already populated with a value different
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200331 * from the one stored in the struct pm_clk_notifier_block object, the function
332 * does nothing.
333 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200334static int pm_clk_notify(struct notifier_block *nb,
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200335 unsigned long action, void *data)
336{
337 struct pm_clk_notifier_block *clknb;
338 struct device *dev = data;
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200339 char **con_id;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200340 int error;
341
342 dev_dbg(dev, "%s() %ld\n", __func__, action);
343
344 clknb = container_of(nb, struct pm_clk_notifier_block, nb);
345
346 switch (action) {
347 case BUS_NOTIFY_ADD_DEVICE:
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200348 if (dev->pm_domain)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200349 break;
350
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200351 error = pm_clk_create(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200352 if (error)
353 break;
354
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200355 dev->pm_domain = clknb->pm_domain;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200356 if (clknb->con_ids[0]) {
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200357 for (con_id = clknb->con_ids; *con_id; con_id++)
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200358 pm_clk_add(dev, *con_id);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200359 } else {
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200360 pm_clk_add(dev, NULL);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200361 }
362
363 break;
364 case BUS_NOTIFY_DEL_DEVICE:
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200365 if (dev->pm_domain != clknb->pm_domain)
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200366 break;
367
Rafael J. Wysocki564b9052011-06-23 01:52:55 +0200368 dev->pm_domain = NULL;
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200369 pm_clk_destroy(dev);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200370 break;
371 }
372
373 return 0;
374}
375
376#else /* !CONFIG_PM_RUNTIME */
377
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200378#ifdef CONFIG_PM
379
380/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200381 * pm_clk_suspend - Disable clocks in a device's PM clock list.
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200382 * @dev: Device to disable the clocks for.
383 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200384int pm_clk_suspend(struct device *dev)
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200385{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200386 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200387 struct pm_clock_entry *ce;
Rafael J. Wysockib7ab83e2011-08-24 21:40:56 +0200388 unsigned long flags;
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200389
390 dev_dbg(dev, "%s()\n", __func__);
391
392 /* If there is no driver, the clocks are already disabled. */
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200393 if (!psd || !dev->driver)
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200394 return 0;
395
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200396 spin_lock_irqsave(&psd->lock, flags);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200397
Geert Uytterhoevena968bed2014-10-01 20:38:17 +0200398 list_for_each_entry_reverse(ce, &psd->clock_list, node) {
399 if (ce->status < PCE_STATUS_ERROR) {
400 if (ce->status == PCE_STATUS_ENABLED)
401 clk_disable(ce->clk);
402 ce->status = PCE_STATUS_ACQUIRED;
403 }
404 }
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200405
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200406 spin_unlock_irqrestore(&psd->lock, flags);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200407
408 return 0;
409}
410
411/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200412 * pm_clk_resume - Enable clocks in a device's PM clock list.
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200413 * @dev: Device to enable the clocks for.
414 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200415int pm_clk_resume(struct device *dev)
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200416{
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200417 struct pm_subsys_data *psd = dev_to_psd(dev);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200418 struct pm_clock_entry *ce;
Rafael J. Wysockib7ab83e2011-08-24 21:40:56 +0200419 unsigned long flags;
Geert Uytterhoevena968bed2014-10-01 20:38:17 +0200420 int ret;
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200421
422 dev_dbg(dev, "%s()\n", __func__);
423
424 /* If there is no driver, the clocks should remain disabled. */
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200425 if (!psd || !dev->driver)
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200426 return 0;
427
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200428 spin_lock_irqsave(&psd->lock, flags);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200429
Geert Uytterhoevena968bed2014-10-01 20:38:17 +0200430 list_for_each_entry(ce, &psd->clock_list, node) {
431 if (ce->status < PCE_STATUS_ERROR) {
432 ret = __pm_clk_enable(dev, ce->clk);
433 if (!ret)
434 ce->status = PCE_STATUS_ENABLED;
435 }
436 }
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200437
Rafael J. Wysocki5c095a02011-08-25 15:33:50 +0200438 spin_unlock_irqrestore(&psd->lock, flags);
Rafael J. Wysockib7b95922011-07-01 22:13:37 +0200439
440 return 0;
441}
442
443#endif /* CONFIG_PM */
444
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200445/**
446 * enable_clock - Enable a device clock.
447 * @dev: Device whose clock is to be enabled.
448 * @con_id: Connection ID of the clock.
449 */
450static void enable_clock(struct device *dev, const char *con_id)
451{
452 struct clk *clk;
453
454 clk = clk_get(dev, con_id);
455 if (!IS_ERR(clk)) {
Murali Karicheric122f272012-10-23 01:18:40 +0200456 clk_prepare_enable(clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200457 clk_put(clk);
458 dev_info(dev, "Runtime PM disabled, clock forced on.\n");
459 }
460}
461
462/**
463 * disable_clock - Disable a device clock.
464 * @dev: Device whose clock is to be disabled.
465 * @con_id: Connection ID of the clock.
466 */
467static void disable_clock(struct device *dev, const char *con_id)
468{
469 struct clk *clk;
470
471 clk = clk_get(dev, con_id);
472 if (!IS_ERR(clk)) {
Murali Karicheric122f272012-10-23 01:18:40 +0200473 clk_disable_unprepare(clk);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200474 clk_put(clk);
475 dev_info(dev, "Runtime PM disabled, clock forced off.\n");
476 }
477}
478
479/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200480 * pm_clk_notify - Notify routine for device addition and removal.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200481 * @nb: Notifier block object this function is a member of.
482 * @action: Operation being carried out by the caller.
483 * @data: Device the routine is being run for.
484 *
485 * For this function to work, @nb must be a member of an object of type
486 * struct pm_clk_notifier_block containing all of the requisite data.
487 * Specifically, the con_ids member of that object is used to enable or disable
488 * the device's clocks, depending on @action.
489 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200490static int pm_clk_notify(struct notifier_block *nb,
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200491 unsigned long action, void *data)
492{
493 struct pm_clk_notifier_block *clknb;
494 struct device *dev = data;
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200495 char **con_id;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200496
497 dev_dbg(dev, "%s() %ld\n", __func__, action);
498
499 clknb = container_of(nb, struct pm_clk_notifier_block, nb);
500
501 switch (action) {
Rafael J. Wysocki4d1518f2011-06-21 23:24:33 +0200502 case BUS_NOTIFY_BIND_DRIVER:
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200503 if (clknb->con_ids[0]) {
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200504 for (con_id = clknb->con_ids; *con_id; con_id++)
505 enable_clock(dev, *con_id);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200506 } else {
507 enable_clock(dev, NULL);
508 }
509 break;
Rafael J. Wysocki4d1518f2011-06-21 23:24:33 +0200510 case BUS_NOTIFY_UNBOUND_DRIVER:
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200511 if (clknb->con_ids[0]) {
Rafael J. Wysocki3b3eca32011-06-07 23:34:58 +0200512 for (con_id = clknb->con_ids; *con_id; con_id++)
513 disable_clock(dev, *con_id);
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200514 } else {
515 disable_clock(dev, NULL);
516 }
517 break;
518 }
519
520 return 0;
521}
522
523#endif /* !CONFIG_PM_RUNTIME */
524
525/**
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200526 * pm_clk_add_notifier - Add bus type notifier for power management clocks.
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200527 * @bus: Bus type to add the notifier to.
528 * @clknb: Notifier to be added to the given bus type.
529 *
530 * The nb member of @clknb is not expected to be initialized and its
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200531 * notifier_call member will be replaced with pm_clk_notify(). However,
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200532 * the remaining members of @clknb should be populated prior to calling this
533 * routine.
534 */
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200535void pm_clk_add_notifier(struct bus_type *bus,
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200536 struct pm_clk_notifier_block *clknb)
537{
538 if (!bus || !clknb)
539 return;
540
Rafael J. Wysocki3d5c3032011-07-01 22:13:44 +0200541 clknb->nb.notifier_call = pm_clk_notify;
Rafael J. Wysocki85eb8c82011-04-30 00:25:44 +0200542 bus_register_notifier(bus, &clknb->nb);
543}