clock_ops.c 11.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 * 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>
11
#include <linux/device.h>
12 13
#include <linux/io.h>
#include <linux/pm.h>
14
#include <linux/pm_clock.h>
15 16 17 18
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/err.h>

19
#ifdef CONFIG_PM
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50
/**
 * pm_clk_acquire - Acquire a device clock.
 * @dev: Device whose clock is to be acquired.
 * @ce: PM clock entry corresponding to the clock.
 */
static void pm_clk_acquire(struct device *dev, 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);
	}
}

51
/**
52 53
 * pm_clk_add - Start using a device clock for power management.
 * @dev: Device whose clock is going to be used for power management.
54 55 56
 * @con_id: Connection ID of the clock.
 *
 * Add the clock represented by @con_id to the list of clocks used for
57
 * the power management of @dev.
58
 */
59
int pm_clk_add(struct device *dev, const char *con_id)
60
{
61
	struct pm_subsys_data *psd = dev_to_psd(dev);
62 63
	struct pm_clock_entry *ce;

64
	if (!psd)
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
		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;
		}
	}

83 84
	pm_clk_acquire(dev, ce);

85 86 87
	spin_lock_irq(&psd->lock);
	list_add_tail(&ce->node, &psd->clock_list);
	spin_unlock_irq(&psd->lock);
88 89 90 91
	return 0;
}

/**
92 93
 * __pm_clk_remove - Destroy PM clock entry.
 * @ce: PM clock entry to destroy.
94
 */
95
static void __pm_clk_remove(struct pm_clock_entry *ce)
96 97 98 99 100 101 102 103 104 105 106 107
{
	if (!ce)
		return;

	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);
	}

108
	kfree(ce->con_id);
109 110 111 112
	kfree(ce);
}

/**
113 114
 * pm_clk_remove - Stop using a device clock for power management.
 * @dev: Device whose clock should not be used for PM any more.
115 116 117
 * @con_id: Connection ID of the clock.
 *
 * Remove the clock represented by @con_id from the list of clocks used for
118
 * the power management of @dev.
119
 */
120
void pm_clk_remove(struct device *dev, const char *con_id)
121
{
122
	struct pm_subsys_data *psd = dev_to_psd(dev);
123 124
	struct pm_clock_entry *ce;

125
	if (!psd)
126 127
		return;

128
	spin_lock_irq(&psd->lock);
129

130
	list_for_each_entry(ce, &psd->clock_list, node) {
131 132 133
		if (!con_id && !ce->con_id)
			goto remove;
		else if (!con_id || !ce->con_id)
134
			continue;
135 136
		else if (!strcmp(con_id, ce->con_id))
			goto remove;
137 138
	}

139
	spin_unlock_irq(&psd->lock);
140 141 142 143
	return;

 remove:
	list_del(&ce->node);
144
	spin_unlock_irq(&psd->lock);
145 146

	__pm_clk_remove(ce);
147 148 149
}

/**
150 151
 * pm_clk_init - Initialize a device's list of power management clocks.
 * @dev: Device to initialize the list of PM clocks for.
152
 *
153 154
 * Initialize the lock and clock_list members of the device's pm_subsys_data
 * object.
155
 */
156
void pm_clk_init(struct device *dev)
157
{
158
	struct pm_subsys_data *psd = dev_to_psd(dev);
159 160
	if (psd)
		INIT_LIST_HEAD(&psd->clock_list);
161 162 163 164 165 166 167 168 169 170 171
}

/**
 * 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)
{
172
	return dev_pm_get_subsys_data(dev);
173 174 175
}

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

189
	if (!psd)
190 191
		return;

192
	INIT_LIST_HEAD(&list);
193

194
	spin_lock_irq(&psd->lock);
195

196
	list_for_each_entry_safe_reverse(ce, c, &psd->clock_list, node)
197
		list_move(&ce->node, &list);
198

199
	spin_unlock_irq(&psd->lock);
200

201
	dev_pm_put_subsys_data(dev);
202 203 204 205 206

	list_for_each_entry_safe_reverse(ce, c, &list, node) {
		list_del(&ce->node);
		__pm_clk_remove(ce);
	}
207 208
}

209 210 211 212
#endif /* CONFIG_PM */

#ifdef CONFIG_PM_RUNTIME

213
/**
214
 * pm_clk_suspend - Disable clocks in a device's PM clock list.
215 216
 * @dev: Device to disable the clocks for.
 */
217
int pm_clk_suspend(struct device *dev)
218
{
219
	struct pm_subsys_data *psd = dev_to_psd(dev);
220
	struct pm_clock_entry *ce;
221
	unsigned long flags;
222 223 224

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

225
	if (!psd)
226 227
		return 0;

228
	spin_lock_irqsave(&psd->lock, flags);
229

230
	list_for_each_entry_reverse(ce, &psd->clock_list, node) {
231
		if (ce->status < PCE_STATUS_ERROR) {
232 233
			if (ce->status == PCE_STATUS_ENABLED)
				clk_disable(ce->clk);
234 235 236 237
			ce->status = PCE_STATUS_ACQUIRED;
		}
	}

238
	spin_unlock_irqrestore(&psd->lock, flags);
239 240 241 242 243

	return 0;
}

/**
244
 * pm_clk_resume - Enable clocks in a device's PM clock list.
245 246
 * @dev: Device to enable the clocks for.
 */
247
int pm_clk_resume(struct device *dev)
248
{
249
	struct pm_subsys_data *psd = dev_to_psd(dev);
250
	struct pm_clock_entry *ce;
251
	unsigned long flags;
252 253 254

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

255
	if (!psd)
256 257
		return 0;

258
	spin_lock_irqsave(&psd->lock, flags);
259

260
	list_for_each_entry(ce, &psd->clock_list, node) {
261 262 263 264 265 266
		if (ce->status < PCE_STATUS_ERROR) {
			clk_enable(ce->clk);
			ce->status = PCE_STATUS_ENABLED;
		}
	}

267
	spin_unlock_irqrestore(&psd->lock, flags);
268 269 270 271 272

	return 0;
}

/**
273
 * pm_clk_notify - Notify routine for device addition and removal.
274 275 276 277 278 279
 * @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.
280 281
 * 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
282
 * of PM clocks, depending on @action.
283
 *
284
 * If the device's pm_domain field is already populated with a value different
285 286 287
 * from the one stored in the struct pm_clk_notifier_block object, the function
 * does nothing.
 */
288
static int pm_clk_notify(struct notifier_block *nb,
289 290 291 292
				 unsigned long action, void *data)
{
	struct pm_clk_notifier_block *clknb;
	struct device *dev = data;
293
	char **con_id;
294 295 296 297 298 299 300 301
	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:
302
		if (dev->pm_domain)
303 304
			break;

305
		error = pm_clk_create(dev);
306 307 308
		if (error)
			break;

309
		dev->pm_domain = clknb->pm_domain;
310
		if (clknb->con_ids[0]) {
311
			for (con_id = clknb->con_ids; *con_id; con_id++)
312
				pm_clk_add(dev, *con_id);
313
		} else {
314
			pm_clk_add(dev, NULL);
315 316 317 318
		}

		break;
	case BUS_NOTIFY_DEL_DEVICE:
319
		if (dev->pm_domain != clknb->pm_domain)
320 321
			break;

322
		dev->pm_domain = NULL;
323
		pm_clk_destroy(dev);
324 325 326 327 328 329 330 331
		break;
	}

	return 0;
}

#else /* !CONFIG_PM_RUNTIME */

332 333 334
#ifdef CONFIG_PM

/**
335
 * pm_clk_suspend - Disable clocks in a device's PM clock list.
336 337
 * @dev: Device to disable the clocks for.
 */
338
int pm_clk_suspend(struct device *dev)
339
{
340
	struct pm_subsys_data *psd = dev_to_psd(dev);
341
	struct pm_clock_entry *ce;
342
	unsigned long flags;
343 344 345 346

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

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

350
	spin_lock_irqsave(&psd->lock, flags);
351

352
	list_for_each_entry_reverse(ce, &psd->clock_list, node)
353 354
		clk_disable(ce->clk);

355
	spin_unlock_irqrestore(&psd->lock, flags);
356 357 358 359 360

	return 0;
}

/**
361
 * pm_clk_resume - Enable clocks in a device's PM clock list.
362 363
 * @dev: Device to enable the clocks for.
 */
364
int pm_clk_resume(struct device *dev)
365
{
366
	struct pm_subsys_data *psd = dev_to_psd(dev);
367
	struct pm_clock_entry *ce;
368
	unsigned long flags;
369 370 371 372

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

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

376
	spin_lock_irqsave(&psd->lock, flags);
377

378
	list_for_each_entry(ce, &psd->clock_list, node)
379 380
		clk_enable(ce->clk);

381
	spin_unlock_irqrestore(&psd->lock, flags);
382 383 384 385 386 387

	return 0;
}

#endif /* CONFIG_PM */

388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422
/**
 * 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");
	}
}

/**
423
 * pm_clk_notify - Notify routine for device addition and removal.
424 425 426 427 428 429 430 431 432
 * @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.
 */
433
static int pm_clk_notify(struct notifier_block *nb,
434 435 436 437
				 unsigned long action, void *data)
{
	struct pm_clk_notifier_block *clknb;
	struct device *dev = data;
438
	char **con_id;
439 440 441 442 443 444

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

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

	switch (action) {
445
	case BUS_NOTIFY_BIND_DRIVER:
446
		if (clknb->con_ids[0]) {
447 448
			for (con_id = clknb->con_ids; *con_id; con_id++)
				enable_clock(dev, *con_id);
449 450 451 452
		} else {
			enable_clock(dev, NULL);
		}
		break;
453
	case BUS_NOTIFY_UNBOUND_DRIVER:
454
		if (clknb->con_ids[0]) {
455 456
			for (con_id = clknb->con_ids; *con_id; con_id++)
				disable_clock(dev, *con_id);
457 458 459 460 461 462 463 464 465 466 467 468
		} else {
			disable_clock(dev, NULL);
		}
		break;
	}

	return 0;
}

#endif /* !CONFIG_PM_RUNTIME */

/**
469
 * pm_clk_add_notifier - Add bus type notifier for power management clocks.
470 471 472 473
 * @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
474
 * notifier_call member will be replaced with pm_clk_notify().  However,
475 476 477
 * the remaining members of @clknb should be populated prior to calling this
 * routine.
 */
478
void pm_clk_add_notifier(struct bus_type *bus,
479 480 481 482 483
				 struct pm_clk_notifier_block *clknb)
{
	if (!bus || !clknb)
		return;

484
	clknb->nb.notifier_call = pm_clk_notify;
485 486
	bus_register_notifier(bus, &clknb->nb);
}