clock_ops.c 11.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks
 *
 * Copyright (c) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
 *
 * This file is released under the GPLv2.
 */

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/err.h>

18
#ifdef CONFIG_PM
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

enum pce_status {
	PCE_STATUS_NONE = 0,
	PCE_STATUS_ACQUIRED,
	PCE_STATUS_ENABLED,
	PCE_STATUS_ERROR,
};

struct pm_clock_entry {
	struct list_head node;
	char *con_id;
	struct clk *clk;
	enum pce_status status;
};

/**
35 36
 * pm_clk_add - Start using a device clock for power management.
 * @dev: Device whose clock is going to be used for power management.
37 38 39
 * @con_id: Connection ID of the clock.
 *
 * Add the clock represented by @con_id to the list of clocks used for
40
 * the power management of @dev.
41
 */
42
int pm_clk_add(struct device *dev, const char *con_id)
43
{
44
	struct pm_subsys_data *psd = dev_to_psd(dev);
45 46
	struct pm_clock_entry *ce;

47
	if (!psd)
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
		return -EINVAL;

	ce = kzalloc(sizeof(*ce), GFP_KERNEL);
	if (!ce) {
		dev_err(dev, "Not enough memory for clock entry.\n");
		return -ENOMEM;
	}

	if (con_id) {
		ce->con_id = kstrdup(con_id, GFP_KERNEL);
		if (!ce->con_id) {
			dev_err(dev,
				"Not enough memory for clock connection ID.\n");
			kfree(ce);
			return -ENOMEM;
		}
	}

66 67 68
	spin_lock_irq(&psd->lock);
	list_add_tail(&ce->node, &psd->clock_list);
	spin_unlock_irq(&psd->lock);
69 70 71 72
	return 0;
}

/**
73 74
 * __pm_clk_remove - Destroy PM clock entry.
 * @ce: PM clock entry to destroy.
75
 *
76 77
 * This routine must be called under the spinlock protecting the PM list of
 * clocks corresponding the the @ce's device.
78
 */
79
static void __pm_clk_remove(struct pm_clock_entry *ce)
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
{
	if (!ce)
		return;

	list_del(&ce->node);

	if (ce->status < PCE_STATUS_ERROR) {
		if (ce->status == PCE_STATUS_ENABLED)
			clk_disable(ce->clk);

		if (ce->status >= PCE_STATUS_ACQUIRED)
			clk_put(ce->clk);
	}

	if (ce->con_id)
		kfree(ce->con_id);

	kfree(ce);
}

/**
101 102
 * pm_clk_remove - Stop using a device clock for power management.
 * @dev: Device whose clock should not be used for PM any more.
103 104 105
 * @con_id: Connection ID of the clock.
 *
 * Remove the clock represented by @con_id from the list of clocks used for
106
 * the power management of @dev.
107
 */
108
void pm_clk_remove(struct device *dev, const char *con_id)
109
{
110
	struct pm_subsys_data *psd = dev_to_psd(dev);
111 112
	struct pm_clock_entry *ce;

113
	if (!psd)
114 115
		return;

116
	spin_lock_irq(&psd->lock);
117

118
	list_for_each_entry(ce, &psd->clock_list, node) {
119
		if (!con_id && !ce->con_id) {
120
			__pm_clk_remove(ce);
121 122 123 124
			break;
		} else if (!con_id || !ce->con_id) {
			continue;
		} else if (!strcmp(con_id, ce->con_id)) {
125
			__pm_clk_remove(ce);
126 127 128 129
			break;
		}
	}

130
	spin_unlock_irq(&psd->lock);
131 132 133
}

/**
134 135
 * pm_clk_init - Initialize a device's list of power management clocks.
 * @dev: Device to initialize the list of PM clocks for.
136
 *
137 138
 * Initialize the lock and clock_list members of the device's pm_subsys_data
 * object.
139
 */
140
void pm_clk_init(struct device *dev)
141
{
142 143 144 145
	struct pm_subsys_data *psd = dev_to_psd(dev);

	if (!psd)
		return;
146

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
	INIT_LIST_HEAD(&psd->clock_list);
	spin_lock_init(&psd->lock);
}

/**
 * pm_clk_create - Create and initialize a device's list of PM clocks.
 * @dev: Device to create and initialize the list of PM clocks for.
 *
 * Allocate a struct pm_subsys_data object, initialize its lock and clock_list
 * members and make the @dev's power.subsys_data field point to it.
 */
int pm_clk_create(struct device *dev)
{
	struct pm_subsys_data *psd;

	psd = kzalloc(sizeof(*psd), GFP_KERNEL);
	if (!psd) {
164
		dev_err(dev, "Not enough memory for PM clock data.\n");
165 166
		return -ENOMEM;
	}
167 168
	dev->power.subsys_data = psd;
	pm_clk_init(dev);
169 170 171 172
	return 0;
}

/**
173 174
 * pm_clk_destroy - Destroy a device's list of power management clocks.
 * @dev: Device to destroy the list of PM clocks for.
175 176
 *
 * Clear the @dev's power.subsys_data field, remove the list of clock entries
177
 * from the struct pm_subsys_data object pointed to by it before and free
178 179
 * that object.
 */
180
void pm_clk_destroy(struct device *dev)
181
{
182
	struct pm_subsys_data *psd = dev_to_psd(dev);
183 184
	struct pm_clock_entry *ce, *c;

185
	if (!psd)
186 187 188 189
		return;

	dev->power.subsys_data = NULL;

190
	spin_lock_irq(&psd->lock);
191

192
	list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
193
		__pm_clk_remove(ce);
194

195
	spin_unlock_irq(&psd->lock);
196

197
	kfree(psd);
198 199
}

200 201 202 203
#endif /* CONFIG_PM */

#ifdef CONFIG_PM_RUNTIME

204
/**
205
 * pm_clk_acquire - Acquire a device clock.
206 207 208
 * @dev: Device whose clock is to be acquired.
 * @con_id: Connection ID of the clock.
 */
209
static void pm_clk_acquire(struct device *dev,
210 211 212 213 214 215 216 217 218 219 220 221
				    struct pm_clock_entry *ce)
{
	ce->clk = clk_get(dev, ce->con_id);
	if (IS_ERR(ce->clk)) {
		ce->status = PCE_STATUS_ERROR;
	} else {
		ce->status = PCE_STATUS_ACQUIRED;
		dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
	}
}

/**
222
 * pm_clk_suspend - Disable clocks in a device's PM clock list.
223 224
 * @dev: Device to disable the clocks for.
 */
225
int pm_clk_suspend(struct device *dev)
226
{
227
	struct pm_subsys_data *psd = dev_to_psd(dev);
228
	struct pm_clock_entry *ce;
229
	unsigned long flags;
230 231 232

	dev_dbg(dev, "%s()\n", __func__);

233
	if (!psd)
234 235
		return 0;

236
	spin_lock_irqsave(&psd->lock, flags);
237

238
	list_for_each_entry_reverse(ce, &psd->clock_list, node) {
239
		if (ce->status == PCE_STATUS_NONE)
240
			pm_clk_acquire(dev, ce);
241 242 243 244 245 246 247

		if (ce->status < PCE_STATUS_ERROR) {
			clk_disable(ce->clk);
			ce->status = PCE_STATUS_ACQUIRED;
		}
	}

248
	spin_unlock_irqrestore(&psd->lock, flags);
249 250 251 252 253

	return 0;
}

/**
254
 * pm_clk_resume - Enable clocks in a device's PM clock list.
255 256
 * @dev: Device to enable the clocks for.
 */
257
int pm_clk_resume(struct device *dev)
258
{
259
	struct pm_subsys_data *psd = dev_to_psd(dev);
260
	struct pm_clock_entry *ce;
261
	unsigned long flags;
262 263 264

	dev_dbg(dev, "%s()\n", __func__);

265
	if (!psd)
266 267
		return 0;

268
	spin_lock_irqsave(&psd->lock, flags);
269

270
	list_for_each_entry(ce, &psd->clock_list, node) {
271
		if (ce->status == PCE_STATUS_NONE)
272
			pm_clk_acquire(dev, ce);
273 274 275 276 277 278 279

		if (ce->status < PCE_STATUS_ERROR) {
			clk_enable(ce->clk);
			ce->status = PCE_STATUS_ENABLED;
		}
	}

280
	spin_unlock_irqrestore(&psd->lock, flags);
281 282 283 284 285

	return 0;
}

/**
286
 * pm_clk_notify - Notify routine for device addition and removal.
287 288 289 290 291 292
 * @nb: Notifier block object this function is a member of.
 * @action: Operation being carried out by the caller.
 * @data: Device the routine is being run for.
 *
 * For this function to work, @nb must be a member of an object of type
 * struct pm_clk_notifier_block containing all of the requisite data.
293 294
 * Specifically, the pm_domain member of that object is copied to the device's
 * pm_domain field and its con_ids member is used to populate the device's list
295
 * of PM clocks, depending on @action.
296
 *
297
 * If the device's pm_domain field is already populated with a value different
298 299 300
 * from the one stored in the struct pm_clk_notifier_block object, the function
 * does nothing.
 */
301
static int pm_clk_notify(struct notifier_block *nb,
302 303 304 305
				 unsigned long action, void *data)
{
	struct pm_clk_notifier_block *clknb;
	struct device *dev = data;
306
	char **con_id;
307 308 309 310 311 312 313 314
	int error;

	dev_dbg(dev, "%s() %ld\n", __func__, action);

	clknb = container_of(nb, struct pm_clk_notifier_block, nb);

	switch (action) {
	case BUS_NOTIFY_ADD_DEVICE:
315
		if (dev->pm_domain)
316 317
			break;

318
		error = pm_clk_create(dev);
319 320 321
		if (error)
			break;

322
		dev->pm_domain = clknb->pm_domain;
323
		if (clknb->con_ids[0]) {
324
			for (con_id = clknb->con_ids; *con_id; con_id++)
325
				pm_clk_add(dev, *con_id);
326
		} else {
327
			pm_clk_add(dev, NULL);
328 329 330 331
		}

		break;
	case BUS_NOTIFY_DEL_DEVICE:
332
		if (dev->pm_domain != clknb->pm_domain)
333 334
			break;

335
		dev->pm_domain = NULL;
336
		pm_clk_destroy(dev);
337 338 339 340 341 342 343 344
		break;
	}

	return 0;
}

#else /* !CONFIG_PM_RUNTIME */

345 346 347
#ifdef CONFIG_PM

/**
348
 * pm_clk_suspend - Disable clocks in a device's PM clock list.
349 350
 * @dev: Device to disable the clocks for.
 */
351
int pm_clk_suspend(struct device *dev)
352
{
353
	struct pm_subsys_data *psd = dev_to_psd(dev);
354
	struct pm_clock_entry *ce;
355
	unsigned long flags;
356 357 358 359

	dev_dbg(dev, "%s()\n", __func__);

	/* If there is no driver, the clocks are already disabled. */
360
	if (!psd || !dev->driver)
361 362
		return 0;

363
	spin_lock_irqsave(&psd->lock, flags);
364

365
	list_for_each_entry_reverse(ce, &psd->clock_list, node)
366 367
		clk_disable(ce->clk);

368
	spin_unlock_irqrestore(&psd->lock, flags);
369 370 371 372 373

	return 0;
}

/**
374
 * pm_clk_resume - Enable clocks in a device's PM clock list.
375 376
 * @dev: Device to enable the clocks for.
 */
377
int pm_clk_resume(struct device *dev)
378
{
379
	struct pm_subsys_data *psd = dev_to_psd(dev);
380
	struct pm_clock_entry *ce;
381
	unsigned long flags;
382 383 384 385

	dev_dbg(dev, "%s()\n", __func__);

	/* If there is no driver, the clocks should remain disabled. */
386
	if (!psd || !dev->driver)
387 388
		return 0;

389
	spin_lock_irqsave(&psd->lock, flags);
390

391
	list_for_each_entry(ce, &psd->clock_list, node)
392 393
		clk_enable(ce->clk);

394
	spin_unlock_irqrestore(&psd->lock, flags);
395 396 397 398 399 400

	return 0;
}

#endif /* CONFIG_PM */

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
/**
 * enable_clock - Enable a device clock.
 * @dev: Device whose clock is to be enabled.
 * @con_id: Connection ID of the clock.
 */
static void enable_clock(struct device *dev, const char *con_id)
{
	struct clk *clk;

	clk = clk_get(dev, con_id);
	if (!IS_ERR(clk)) {
		clk_enable(clk);
		clk_put(clk);
		dev_info(dev, "Runtime PM disabled, clock forced on.\n");
	}
}

/**
 * disable_clock - Disable a device clock.
 * @dev: Device whose clock is to be disabled.
 * @con_id: Connection ID of the clock.
 */
static void disable_clock(struct device *dev, const char *con_id)
{
	struct clk *clk;

	clk = clk_get(dev, con_id);
	if (!IS_ERR(clk)) {
		clk_disable(clk);
		clk_put(clk);
		dev_info(dev, "Runtime PM disabled, clock forced off.\n");
	}
}

/**
436
 * pm_clk_notify - Notify routine for device addition and removal.
437 438 439 440 441 442 443 444 445
 * @nb: Notifier block object this function is a member of.
 * @action: Operation being carried out by the caller.
 * @data: Device the routine is being run for.
 *
 * For this function to work, @nb must be a member of an object of type
 * struct pm_clk_notifier_block containing all of the requisite data.
 * Specifically, the con_ids member of that object is used to enable or disable
 * the device's clocks, depending on @action.
 */
446
static int pm_clk_notify(struct notifier_block *nb,
447 448 449 450
				 unsigned long action, void *data)
{
	struct pm_clk_notifier_block *clknb;
	struct device *dev = data;
451
	char **con_id;
452 453 454 455 456 457

	dev_dbg(dev, "%s() %ld\n", __func__, action);

	clknb = container_of(nb, struct pm_clk_notifier_block, nb);

	switch (action) {
458
	case BUS_NOTIFY_BIND_DRIVER:
459
		if (clknb->con_ids[0]) {
460 461
			for (con_id = clknb->con_ids; *con_id; con_id++)
				enable_clock(dev, *con_id);
462 463 464 465
		} else {
			enable_clock(dev, NULL);
		}
		break;
466
	case BUS_NOTIFY_UNBOUND_DRIVER:
467
		if (clknb->con_ids[0]) {
468 469
			for (con_id = clknb->con_ids; *con_id; con_id++)
				disable_clock(dev, *con_id);
470 471 472 473 474 475 476 477 478 479 480 481
		} else {
			disable_clock(dev, NULL);
		}
		break;
	}

	return 0;
}

#endif /* !CONFIG_PM_RUNTIME */

/**
482
 * pm_clk_add_notifier - Add bus type notifier for power management clocks.
483 484 485 486
 * @bus: Bus type to add the notifier to.
 * @clknb: Notifier to be added to the given bus type.
 *
 * The nb member of @clknb is not expected to be initialized and its
487
 * notifier_call member will be replaced with pm_clk_notify().  However,
488 489 490
 * the remaining members of @clknb should be populated prior to calling this
 * routine.
 */
491
void pm_clk_add_notifier(struct bus_type *bus,
492 493 494 495 496
				 struct pm_clk_notifier_block *clknb)
{
	if (!bus || !clknb)
		return;

497
	clknb->nb.notifier_call = pm_clk_notify;
498 499
	bus_register_notifier(bus, &clknb->nb);
}