Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.1 494 lines 11 kB view raw
1/* 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 9#include <linux/init.h> 10#include <linux/kernel.h> 11#include <linux/io.h> 12#include <linux/pm.h> 13#include <linux/pm_runtime.h> 14#include <linux/clk.h> 15#include <linux/slab.h> 16#include <linux/err.h> 17 18#ifdef CONFIG_PM 19 20struct pm_clk_data { 21 struct list_head clock_list; 22 spinlock_t lock; 23}; 24 25enum pce_status { 26 PCE_STATUS_NONE = 0, 27 PCE_STATUS_ACQUIRED, 28 PCE_STATUS_ENABLED, 29 PCE_STATUS_ERROR, 30}; 31 32struct pm_clock_entry { 33 struct list_head node; 34 char *con_id; 35 struct clk *clk; 36 enum pce_status status; 37}; 38 39static struct pm_clk_data *__to_pcd(struct device *dev) 40{ 41 return dev ? dev->power.subsys_data : NULL; 42} 43 44/** 45 * pm_clk_acquire - Acquire a device clock. 46 * @dev: Device whose clock is to be acquired. 47 * @ce: PM clock entry corresponding to the clock. 48 */ 49static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce) 50{ 51 ce->clk = clk_get(dev, ce->con_id); 52 if (IS_ERR(ce->clk)) { 53 ce->status = PCE_STATUS_ERROR; 54 } else { 55 ce->status = PCE_STATUS_ACQUIRED; 56 dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id); 57 } 58} 59 60/** 61 * pm_clk_add - Start using a device clock for power management. 62 * @dev: Device whose clock is going to be used for power management. 63 * @con_id: Connection ID of the clock. 64 * 65 * Add the clock represented by @con_id to the list of clocks used for 66 * the power management of @dev. 67 */ 68int pm_clk_add(struct device *dev, const char *con_id) 69{ 70 struct pm_clk_data *pcd = __to_pcd(dev); 71 struct pm_clock_entry *ce; 72 73 if (!pcd) 74 return -EINVAL; 75 76 ce = kzalloc(sizeof(*ce), GFP_KERNEL); 77 if (!ce) { 78 dev_err(dev, "Not enough memory for clock entry.\n"); 79 return -ENOMEM; 80 } 81 82 if (con_id) { 83 ce->con_id = kstrdup(con_id, GFP_KERNEL); 84 if (!ce->con_id) { 85 dev_err(dev, 86 "Not enough memory for clock connection ID.\n"); 87 kfree(ce); 88 return -ENOMEM; 89 } 90 } 91 92 pm_clk_acquire(dev, ce); 93 94 spin_lock_irq(&pcd->lock); 95 list_add_tail(&ce->node, &pcd->clock_list); 96 spin_unlock_irq(&pcd->lock); 97 return 0; 98} 99 100/** 101 * __pm_clk_remove - Destroy PM clock entry. 102 * @ce: PM clock entry to destroy. 103 */ 104static void __pm_clk_remove(struct pm_clock_entry *ce) 105{ 106 if (!ce) 107 return; 108 109 if (ce->status < PCE_STATUS_ERROR) { 110 if (ce->status == PCE_STATUS_ENABLED) 111 clk_disable(ce->clk); 112 113 if (ce->status >= PCE_STATUS_ACQUIRED) 114 clk_put(ce->clk); 115 } 116 117 if (ce->con_id) 118 kfree(ce->con_id); 119 120 kfree(ce); 121} 122 123/** 124 * pm_clk_remove - Stop using a device clock for power management. 125 * @dev: Device whose clock should not be used for PM any more. 126 * @con_id: Connection ID of the clock. 127 * 128 * Remove the clock represented by @con_id from the list of clocks used for 129 * the power management of @dev. 130 */ 131void pm_clk_remove(struct device *dev, const char *con_id) 132{ 133 struct pm_clk_data *pcd = __to_pcd(dev); 134 struct pm_clock_entry *ce; 135 136 if (!pcd) 137 return; 138 139 spin_lock_irq(&pcd->lock); 140 141 list_for_each_entry(ce, &pcd->clock_list, node) { 142 if (!con_id && !ce->con_id) 143 goto remove; 144 else if (!con_id || !ce->con_id) 145 continue; 146 else if (!strcmp(con_id, ce->con_id)) 147 goto remove; 148 } 149 150 spin_unlock_irq(&pcd->lock); 151 return; 152 153 remove: 154 list_del(&ce->node); 155 spin_unlock_irq(&pcd->lock); 156 157 __pm_clk_remove(ce); 158} 159 160/** 161 * pm_clk_init - Initialize a device's list of power management clocks. 162 * @dev: Device to initialize the list of PM clocks for. 163 * 164 * Allocate a struct pm_clk_data object, initialize its lock member and 165 * make the @dev's power.subsys_data field point to it. 166 */ 167int pm_clk_init(struct device *dev) 168{ 169 struct pm_clk_data *pcd; 170 171 pcd = kzalloc(sizeof(*pcd), GFP_KERNEL); 172 if (!pcd) { 173 dev_err(dev, "Not enough memory for PM clock data.\n"); 174 return -ENOMEM; 175 } 176 177 INIT_LIST_HEAD(&pcd->clock_list); 178 spin_lock_init(&pcd->lock); 179 dev->power.subsys_data = pcd; 180 return 0; 181} 182 183/** 184 * pm_clk_destroy - Destroy a device's list of power management clocks. 185 * @dev: Device to destroy the list of PM clocks for. 186 * 187 * Clear the @dev's power.subsys_data field, remove the list of clock entries 188 * from the struct pm_clk_data object pointed to by it before and free 189 * that object. 190 */ 191void pm_clk_destroy(struct device *dev) 192{ 193 struct pm_clk_data *pcd = __to_pcd(dev); 194 struct pm_clock_entry *ce, *c; 195 struct list_head list; 196 197 if (!pcd) 198 return; 199 200 dev->power.subsys_data = NULL; 201 INIT_LIST_HEAD(&list); 202 203 spin_lock_irq(&pcd->lock); 204 205 list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node) 206 list_move(&ce->node, &list); 207 208 spin_unlock_irq(&pcd->lock); 209 210 kfree(pcd); 211 212 list_for_each_entry_safe_reverse(ce, c, &list, node) { 213 list_del(&ce->node); 214 __pm_clk_remove(ce); 215 } 216} 217 218#endif /* CONFIG_PM */ 219 220#ifdef CONFIG_PM_RUNTIME 221 222/** 223 * pm_clk_suspend - Disable clocks in a device's PM clock list. 224 * @dev: Device to disable the clocks for. 225 */ 226int pm_clk_suspend(struct device *dev) 227{ 228 struct pm_clk_data *pcd = __to_pcd(dev); 229 struct pm_clock_entry *ce; 230 unsigned long flags; 231 232 dev_dbg(dev, "%s()\n", __func__); 233 234 if (!pcd) 235 return 0; 236 237 spin_lock_irqsave(&pcd->lock, flags); 238 239 list_for_each_entry_reverse(ce, &pcd->clock_list, node) { 240 if (ce->status < PCE_STATUS_ERROR) { 241 clk_disable(ce->clk); 242 ce->status = PCE_STATUS_ACQUIRED; 243 } 244 } 245 246 spin_unlock_irqrestore(&pcd->lock, flags); 247 248 return 0; 249} 250 251/** 252 * pm_clk_resume - Enable clocks in a device's PM clock list. 253 * @dev: Device to enable the clocks for. 254 */ 255int pm_clk_resume(struct device *dev) 256{ 257 struct pm_clk_data *pcd = __to_pcd(dev); 258 struct pm_clock_entry *ce; 259 unsigned long flags; 260 261 dev_dbg(dev, "%s()\n", __func__); 262 263 if (!pcd) 264 return 0; 265 266 spin_lock_irqsave(&pcd->lock, flags); 267 268 list_for_each_entry(ce, &pcd->clock_list, node) { 269 if (ce->status < PCE_STATUS_ERROR) { 270 clk_enable(ce->clk); 271 ce->status = PCE_STATUS_ENABLED; 272 } 273 } 274 275 spin_unlock_irqrestore(&pcd->lock, flags); 276 277 return 0; 278} 279 280/** 281 * pm_clk_notify - Notify routine for device addition and removal. 282 * @nb: Notifier block object this function is a member of. 283 * @action: Operation being carried out by the caller. 284 * @data: Device the routine is being run for. 285 * 286 * For this function to work, @nb must be a member of an object of type 287 * struct pm_clk_notifier_block containing all of the requisite data. 288 * Specifically, the pm_domain member of that object is copied to the device's 289 * pm_domain field and its con_ids member is used to populate the device's list 290 * of PM clocks, depending on @action. 291 * 292 * If the device's pm_domain field is already populated with a value different 293 * from the one stored in the struct pm_clk_notifier_block object, the function 294 * does nothing. 295 */ 296static int pm_clk_notify(struct notifier_block *nb, 297 unsigned long action, void *data) 298{ 299 struct pm_clk_notifier_block *clknb; 300 struct device *dev = data; 301 char **con_id; 302 int error; 303 304 dev_dbg(dev, "%s() %ld\n", __func__, action); 305 306 clknb = container_of(nb, struct pm_clk_notifier_block, nb); 307 308 switch (action) { 309 case BUS_NOTIFY_ADD_DEVICE: 310 if (dev->pm_domain) 311 break; 312 313 error = pm_clk_init(dev); 314 if (error) 315 break; 316 317 dev->pm_domain = clknb->pm_domain; 318 if (clknb->con_ids[0]) { 319 for (con_id = clknb->con_ids; *con_id; con_id++) 320 pm_clk_add(dev, *con_id); 321 } else { 322 pm_clk_add(dev, NULL); 323 } 324 325 break; 326 case BUS_NOTIFY_DEL_DEVICE: 327 if (dev->pm_domain != clknb->pm_domain) 328 break; 329 330 dev->pm_domain = NULL; 331 pm_clk_destroy(dev); 332 break; 333 } 334 335 return 0; 336} 337 338#else /* !CONFIG_PM_RUNTIME */ 339 340#ifdef CONFIG_PM 341 342/** 343 * pm_clk_suspend - Disable clocks in a device's PM clock list. 344 * @dev: Device to disable the clocks for. 345 */ 346int pm_clk_suspend(struct device *dev) 347{ 348 struct pm_clk_data *pcd = __to_pcd(dev); 349 struct pm_clock_entry *ce; 350 unsigned long flags; 351 352 dev_dbg(dev, "%s()\n", __func__); 353 354 /* If there is no driver, the clocks are already disabled. */ 355 if (!pcd || !dev->driver) 356 return 0; 357 358 spin_lock_irqsave(&pcd->lock, flags); 359 360 list_for_each_entry_reverse(ce, &pcd->clock_list, node) 361 clk_disable(ce->clk); 362 363 spin_unlock_irqrestore(&pcd->lock, flags); 364 365 return 0; 366} 367 368/** 369 * pm_clk_resume - Enable clocks in a device's PM clock list. 370 * @dev: Device to enable the clocks for. 371 */ 372int pm_clk_resume(struct device *dev) 373{ 374 struct pm_clk_data *pcd = __to_pcd(dev); 375 struct pm_clock_entry *ce; 376 unsigned long flags; 377 378 dev_dbg(dev, "%s()\n", __func__); 379 380 /* If there is no driver, the clocks should remain disabled. */ 381 if (!pcd || !dev->driver) 382 return 0; 383 384 spin_lock_irqsave(&pcd->lock, flags); 385 386 list_for_each_entry(ce, &pcd->clock_list, node) 387 clk_enable(ce->clk); 388 389 spin_unlock_irqrestore(&pcd->lock, flags); 390 391 return 0; 392} 393 394#endif /* CONFIG_PM */ 395 396/** 397 * enable_clock - Enable a device clock. 398 * @dev: Device whose clock is to be enabled. 399 * @con_id: Connection ID of the clock. 400 */ 401static void enable_clock(struct device *dev, const char *con_id) 402{ 403 struct clk *clk; 404 405 clk = clk_get(dev, con_id); 406 if (!IS_ERR(clk)) { 407 clk_enable(clk); 408 clk_put(clk); 409 dev_info(dev, "Runtime PM disabled, clock forced on.\n"); 410 } 411} 412 413/** 414 * disable_clock - Disable a device clock. 415 * @dev: Device whose clock is to be disabled. 416 * @con_id: Connection ID of the clock. 417 */ 418static void disable_clock(struct device *dev, const char *con_id) 419{ 420 struct clk *clk; 421 422 clk = clk_get(dev, con_id); 423 if (!IS_ERR(clk)) { 424 clk_disable(clk); 425 clk_put(clk); 426 dev_info(dev, "Runtime PM disabled, clock forced off.\n"); 427 } 428} 429 430/** 431 * pm_clk_notify - Notify routine for device addition and removal. 432 * @nb: Notifier block object this function is a member of. 433 * @action: Operation being carried out by the caller. 434 * @data: Device the routine is being run for. 435 * 436 * For this function to work, @nb must be a member of an object of type 437 * struct pm_clk_notifier_block containing all of the requisite data. 438 * Specifically, the con_ids member of that object is used to enable or disable 439 * the device's clocks, depending on @action. 440 */ 441static int pm_clk_notify(struct notifier_block *nb, 442 unsigned long action, void *data) 443{ 444 struct pm_clk_notifier_block *clknb; 445 struct device *dev = data; 446 char **con_id; 447 448 dev_dbg(dev, "%s() %ld\n", __func__, action); 449 450 clknb = container_of(nb, struct pm_clk_notifier_block, nb); 451 452 switch (action) { 453 case BUS_NOTIFY_BIND_DRIVER: 454 if (clknb->con_ids[0]) { 455 for (con_id = clknb->con_ids; *con_id; con_id++) 456 enable_clock(dev, *con_id); 457 } else { 458 enable_clock(dev, NULL); 459 } 460 break; 461 case BUS_NOTIFY_UNBOUND_DRIVER: 462 if (clknb->con_ids[0]) { 463 for (con_id = clknb->con_ids; *con_id; con_id++) 464 disable_clock(dev, *con_id); 465 } else { 466 disable_clock(dev, NULL); 467 } 468 break; 469 } 470 471 return 0; 472} 473 474#endif /* !CONFIG_PM_RUNTIME */ 475 476/** 477 * pm_clk_add_notifier - Add bus type notifier for power management clocks. 478 * @bus: Bus type to add the notifier to. 479 * @clknb: Notifier to be added to the given bus type. 480 * 481 * The nb member of @clknb is not expected to be initialized and its 482 * notifier_call member will be replaced with pm_clk_notify(). However, 483 * the remaining members of @clknb should be populated prior to calling this 484 * routine. 485 */ 486void pm_clk_add_notifier(struct bus_type *bus, 487 struct pm_clk_notifier_block *clknb) 488{ 489 if (!bus || !clknb) 490 return; 491 492 clknb->nb.notifier_call = pm_clk_notify; 493 bus_register_notifier(bus, &clknb->nb); 494}