soc-dapm.c 69.8 KB
Newer Older
1 2 3 4
/*
 * soc-dapm.c  --  ALSA SoC Dynamic Audio Power Management
 *
 * Copyright 2005 Wolfson Microelectronics PLC.
5
 * Author: Liam Girdwood <lrg@slimlogic.co.uk>
6 7 8 9 10 11 12 13 14
 *
 *  This program is free software; you can redistribute  it and/or modify it
 *  under  the terms of  the GNU General  Public License as published by the
 *  Free Software Foundation;  either version 2 of the  License, or (at your
 *  option) any later version.
 *
 *  Features:
 *    o Changes power status of internal codec blocks depending on the
 *      dynamic configuration of codec internal audio paths and active
M
Mark Brown 已提交
15
 *      DACs/ADCs.
16 17 18 19 20
 *    o Platform power domain - can support external components i.e. amps and
 *      mic/meadphone insertion events.
 *    o Automatic Mic Bias support
 *    o Jack insertion power event initiation - e.g. hp insertion will enable
 *      sinks, dacs, etc
21
 *    o Delayed powerdown of audio susbsystem to reduce pops between a quick
22 23 24 25 26 27 28 29 30 31 32 33 34
 *      device reopen.
 *
 *  Todo:
 *    o DAPM power change sequencing - allow for configurable per
 *      codec sequences.
 *    o Support for analogue bias optimisation.
 *    o Support for reduced codec oversampling rates.
 *    o Support for reduced codec bias currents.
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
35
#include <linux/async.h>
36 37 38 39 40
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/jiffies.h>
41
#include <linux/debugfs.h>
42
#include <linux/slab.h>
43 44 45
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
L
Liam Girdwood 已提交
46
#include <sound/soc.h>
47 48
#include <sound/initval.h>

M
Mark Brown 已提交
49 50
#include <trace/events/asoc.h>

51 52
#define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;

53 54
/* dapm power sequences - make this per codec in the future */
static int dapm_up_seq[] = {
55 56 57
	[snd_soc_dapm_pre] = 0,
	[snd_soc_dapm_supply] = 1,
	[snd_soc_dapm_micbias] = 2,
58 59 60 61
	[snd_soc_dapm_aif_in] = 3,
	[snd_soc_dapm_aif_out] = 3,
	[snd_soc_dapm_mic] = 4,
	[snd_soc_dapm_mux] = 5,
62
	[snd_soc_dapm_virt_mux] = 5,
63 64 65 66 67 68
	[snd_soc_dapm_value_mux] = 5,
	[snd_soc_dapm_dac] = 6,
	[snd_soc_dapm_mixer] = 7,
	[snd_soc_dapm_mixer_named_ctl] = 7,
	[snd_soc_dapm_pga] = 8,
	[snd_soc_dapm_adc] = 9,
69
	[snd_soc_dapm_out_drv] = 10,
70 71 72
	[snd_soc_dapm_hp] = 10,
	[snd_soc_dapm_spk] = 10,
	[snd_soc_dapm_post] = 11,
73
};
74

75
static int dapm_down_seq[] = {
76 77 78
	[snd_soc_dapm_pre] = 0,
	[snd_soc_dapm_adc] = 1,
	[snd_soc_dapm_hp] = 2,
79
	[snd_soc_dapm_spk] = 2,
80
	[snd_soc_dapm_out_drv] = 2,
81 82
	[snd_soc_dapm_pga] = 4,
	[snd_soc_dapm_mixer_named_ctl] = 5,
83 84 85 86 87
	[snd_soc_dapm_mixer] = 5,
	[snd_soc_dapm_dac] = 6,
	[snd_soc_dapm_mic] = 7,
	[snd_soc_dapm_micbias] = 8,
	[snd_soc_dapm_mux] = 9,
88
	[snd_soc_dapm_virt_mux] = 9,
89
	[snd_soc_dapm_value_mux] = 9,
90 91 92 93
	[snd_soc_dapm_aif_in] = 10,
	[snd_soc_dapm_aif_out] = 10,
	[snd_soc_dapm_supply] = 11,
	[snd_soc_dapm_post] = 12,
94 95
};

96
static void pop_wait(u32 pop_time)
97 98 99 100 101
{
	if (pop_time)
		schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
}

102
static void pop_dbg(struct device *dev, u32 pop_time, const char *fmt, ...)
103 104
{
	va_list args;
105
	char *buf;
106

107 108
	if (!pop_time)
		return;
109

110 111 112
	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
	if (buf == NULL)
		return;
113

114 115
	va_start(args, fmt);
	vsnprintf(buf, PAGE_SIZE, fmt, args);
116
	dev_info(dev, "%s", buf);
117
	va_end(args);
118 119

	kfree(buf);
120 121
}

122
/* create a new dapm widget */
123
static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
124 125
	const struct snd_soc_dapm_widget *_widget)
{
126
	return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
127 128
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
/* get snd_card from DAPM context */
static inline struct snd_card *dapm_get_snd_card(
	struct snd_soc_dapm_context *dapm)
{
	if (dapm->codec)
		return dapm->codec->card->snd_card;
	else if (dapm->platform)
		return dapm->platform->card->snd_card;
	else
		BUG();

	/* unreachable */
	return NULL;
}

/* get soc_card from DAPM context */
static inline struct snd_soc_card *dapm_get_soc_card(
		struct snd_soc_dapm_context *dapm)
{
	if (dapm->codec)
		return dapm->codec->card;
	else if (dapm->platform)
		return dapm->platform->card;
	else
		BUG();

	/* unreachable */
	return NULL;
}

159 160 161 162
static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg)
{
	if (w->codec)
		return snd_soc_read(w->codec, reg);
163 164 165 166 167
	else if (w->platform)
		return snd_soc_platform_read(w->platform, reg);

	dev_err(w->dapm->dev, "no valid widget read method\n");
	return -1;
168 169 170 171 172 173
}

static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
{
	if (w->codec)
		return snd_soc_write(w->codec, reg, val);
174 175 176 177 178
	else if (w->platform)
		return snd_soc_platform_write(w->platform, reg, val);

	dev_err(w->dapm->dev, "no valid widget write method\n");
	return -1;
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
}

static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
	unsigned short reg, unsigned int mask, unsigned int value)
{
	int change;
	unsigned int old, new;
	int ret;

	ret = soc_widget_read(w, reg);
	if (ret < 0)
		return ret;

	old = ret;
	new = (old & ~mask) | (value & mask);
	change = old != new;
	if (change) {
		ret = soc_widget_write(w, reg, new);
		if (ret < 0)
			return ret;
	}

	return change;
}

204 205
/**
 * snd_soc_dapm_set_bias_level - set the bias level for the system
206
 * @dapm: DAPM context
207 208 209 210 211 212
 * @level: level to configure
 *
 * Configure the bias (power) levels for the SoC audio device.
 *
 * Returns 0 for success else error.
 */
213
static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm,
L
Liam Girdwood 已提交
214
				       enum snd_soc_bias_level level)
215
{
216
	struct snd_soc_card *card = dapm->card;
217 218
	int ret = 0;

M
Mark Brown 已提交
219 220
	trace_snd_soc_bias_level_start(card, level);

221
	if (card && card->set_bias_level)
222
		ret = card->set_bias_level(card, dapm, level);
223 224 225
	if (ret != 0)
		goto out;

226 227 228 229 230 231 232
	if (dapm->codec) {
		if (dapm->codec->driver->set_bias_level)
			ret = dapm->codec->driver->set_bias_level(dapm->codec,
								  level);
		else
			dapm->bias_level = level;
	}
233 234 235 236
	if (ret != 0)
		goto out;

	if (card && card->set_bias_level_post)
237
		ret = card->set_bias_level_post(card, dapm, level);
238
out:
M
Mark Brown 已提交
239 240
	trace_snd_soc_bias_level_done(card, level);

241 242 243
	return ret;
}

244 245 246 247 248 249
/* set up initial codec paths */
static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
	struct snd_soc_dapm_path *p, int i)
{
	switch (w->id) {
	case snd_soc_dapm_switch:
250 251
	case snd_soc_dapm_mixer:
	case snd_soc_dapm_mixer_named_ctl: {
252
		int val;
253
		struct soc_mixer_control *mc = (struct soc_mixer_control *)
254
			w->kcontrol_news[i].private_value;
255 256
		unsigned int reg = mc->reg;
		unsigned int shift = mc->shift;
257
		int max = mc->max;
258 259
		unsigned int mask = (1 << fls(max)) - 1;
		unsigned int invert = mc->invert;
260

261
		val = soc_widget_read(w, reg);
262 263 264 265 266 267 268 269 270
		val = (val >> shift) & mask;

		if ((invert && !val) || (!invert && val))
			p->connect = 1;
		else
			p->connect = 0;
	}
	break;
	case snd_soc_dapm_mux: {
271 272
		struct soc_enum *e = (struct soc_enum *)
			w->kcontrol_news[i].private_value;
273 274
		int val, item, bitmask;

275
		for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
276
			;
277
		val = soc_widget_read(w, e->reg);
278 279 280
		item = (val >> e->shift_l) & (bitmask - 1);

		p->connect = 0;
281
		for (i = 0; i < e->max; i++) {
282 283 284 285 286
			if (!(strcmp(p->name, e->texts[i])) && item == i)
				p->connect = 1;
		}
	}
	break;
287
	case snd_soc_dapm_virt_mux: {
288 289
		struct soc_enum *e = (struct soc_enum *)
			w->kcontrol_news[i].private_value;
290 291 292 293 294 295 296 297 298 299 300 301

		p->connect = 0;
		/* since a virtual mux has no backing registers to
		 * decide which path to connect, it will try to match
		 * with the first enumeration.  This is to ensure
		 * that the default mux choice (the first) will be
		 * correctly powered up during initialization.
		 */
		if (!strcmp(p->name, e->texts[0]))
			p->connect = 1;
	}
	break;
P
Peter Ujfalusi 已提交
302
	case snd_soc_dapm_value_mux: {
303
		struct soc_enum *e = (struct soc_enum *)
304
			w->kcontrol_news[i].private_value;
P
Peter Ujfalusi 已提交
305 306
		int val, item;

307
		val = soc_widget_read(w, e->reg);
P
Peter Ujfalusi 已提交
308 309 310 311 312 313 314 315 316 317 318 319 320
		val = (val >> e->shift_l) & e->mask;
		for (item = 0; item < e->max; item++) {
			if (val == e->values[item])
				break;
		}

		p->connect = 0;
		for (i = 0; i < e->max; i++) {
			if (!(strcmp(p->name, e->texts[i])) && item == i)
				p->connect = 1;
		}
	}
	break;
321 322
	/* does not effect routing - always connected */
	case snd_soc_dapm_pga:
323
	case snd_soc_dapm_out_drv:
324 325 326 327 328 329
	case snd_soc_dapm_output:
	case snd_soc_dapm_adc:
	case snd_soc_dapm_input:
	case snd_soc_dapm_dac:
	case snd_soc_dapm_micbias:
	case snd_soc_dapm_vmid:
330
	case snd_soc_dapm_supply:
331 332
	case snd_soc_dapm_aif_in:
	case snd_soc_dapm_aif_out:
333 334 335 336 337 338 339 340 341 342 343 344 345 346
		p->connect = 1;
	break;
	/* does effect routing - dynamically connected */
	case snd_soc_dapm_hp:
	case snd_soc_dapm_mic:
	case snd_soc_dapm_spk:
	case snd_soc_dapm_line:
	case snd_soc_dapm_pre:
	case snd_soc_dapm_post:
		p->connect = 0;
	break;
	}
}

M
Mark Brown 已提交
347
/* connect mux widget to its interconnecting audio paths */
L
Liam Girdwood 已提交
348
static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
349 350 351 352 353 354 355
	struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
	struct snd_soc_dapm_path *path, const char *control_name,
	const struct snd_kcontrol_new *kcontrol)
{
	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
	int i;

356
	for (i = 0; i < e->max; i++) {
357
		if (!(strcmp(control_name, e->texts[i]))) {
358
			list_add(&path->list, &dapm->card->paths);
359 360 361 362 363 364 365 366 367 368 369
			list_add(&path->list_sink, &dest->sources);
			list_add(&path->list_source, &src->sinks);
			path->name = (char*)e->texts[i];
			dapm_set_path_status(dest, path, 0);
			return 0;
		}
	}

	return -ENODEV;
}

M
Mark Brown 已提交
370
/* connect mixer widget to its interconnecting audio paths */
L
Liam Girdwood 已提交
371
static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
372 373 374 375 376 377 378
	struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
	struct snd_soc_dapm_path *path, const char *control_name)
{
	int i;

	/* search for mixer kcontrol */
	for (i = 0; i < dest->num_kcontrols; i++) {
379
		if (!strcmp(control_name, dest->kcontrol_news[i].name)) {
380
			list_add(&path->list, &dapm->card->paths);
381 382
			list_add(&path->list_sink, &dest->sources);
			list_add(&path->list_source, &src->sinks);
383
			path->name = dest->kcontrol_news[i].name;
384 385 386 387 388 389 390
			dapm_set_path_status(dest, path, i);
			return 0;
		}
	}
	return -ENODEV;
}

391
static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
392
	struct snd_soc_dapm_widget *kcontrolw,
393 394 395 396 397 398 399 400 401
	const struct snd_kcontrol_new *kcontrol_new,
	struct snd_kcontrol **kcontrol)
{
	struct snd_soc_dapm_widget *w;
	int i;

	*kcontrol = NULL;

	list_for_each_entry(w, &dapm->card->widgets, list) {
402 403
		if (w == kcontrolw || w->dapm != kcontrolw->dapm)
			continue;
404 405 406 407 408 409 410 411 412 413 414 415
		for (i = 0; i < w->num_kcontrols; i++) {
			if (&w->kcontrol_news[i] == kcontrol_new) {
				if (w->kcontrols)
					*kcontrol = w->kcontrols[i];
				return 1;
			}
		}
	}

	return 0;
}

416
/* create new dapm mixer control */
417
static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
418
{
419
	struct snd_soc_dapm_context *dapm = w->dapm;
420
	int i, ret = 0;
421
	size_t name_len, prefix_len;
422
	struct snd_soc_dapm_path *path;
423
	struct snd_card *card = dapm->card->snd_card;
424
	const char *prefix;
425 426
	struct snd_soc_dapm_widget_list *wlist;
	size_t wlistsize;
427 428 429 430 431

	if (dapm->codec)
		prefix = dapm->codec->name_prefix;
	else
		prefix = NULL;
432

433 434 435 436 437
	if (prefix)
		prefix_len = strlen(prefix) + 1;
	else
		prefix_len = 0;

438 439 440 441 442 443 444
	/* add kcontrol */
	for (i = 0; i < w->num_kcontrols; i++) {

		/* match name */
		list_for_each_entry(path, &w->sources, list_sink) {

			/* mixer/mux paths name must match control name */
445
			if (path->name != (char *)w->kcontrol_news[i].name)
446 447
				continue;

448 449 450 451 452
			if (w->kcontrols[i]) {
				path->kcontrol = w->kcontrols[i];
				continue;
			}

453 454 455 456 457 458 459 460 461 462 463 464
			wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
				    sizeof(struct snd_soc_dapm_widget *),
			wlist = kzalloc(wlistsize, GFP_KERNEL);
			if (wlist == NULL) {
				dev_err(dapm->dev,
					"asoc: can't allocate widget list for %s\n",
					w->name);
				return -ENOMEM;
			}
			wlist->num_widgets = 1;
			wlist->widgets[0] = w;

465 466 467 468 469 470
			/* add dapm control with long name.
			 * for dapm_mixer this is the concatenation of the
			 * mixer and kcontrol name.
			 * for dapm_mixer_named_ctl this is simply the
			 * kcontrol name.
			 */
471
			name_len = strlen(w->kcontrol_news[i].name) + 1;
472
			if (w->id != snd_soc_dapm_mixer_named_ctl)
473 474
				name_len += 1 + strlen(w->name);

475
			path->long_name = kmalloc(name_len, GFP_KERNEL);
476

477 478
			if (path->long_name == NULL) {
				kfree(wlist);
479
				return -ENOMEM;
480
			}
481

482 483
			switch (w->id) {
			default:
484 485 486 487 488 489
				/* The control will get a prefix from
				 * the control creation process but
				 * we're also using the same prefix
				 * for widgets so cut the prefix off
				 * the front of the widget name.
				 */
490
				snprintf(path->long_name, name_len, "%s %s",
491
					 w->name + prefix_len,
492
					 w->kcontrol_news[i].name);
493
				break;
494 495
			case snd_soc_dapm_mixer_named_ctl:
				snprintf(path->long_name, name_len, "%s",
496
					 w->kcontrol_news[i].name);
497
				break;
498 499
			}

500 501
			path->long_name[name_len - 1] = '\0';

502 503 504
			path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
						      wlist, path->long_name,
						      prefix);
L
Liam Girdwood 已提交
505
			ret = snd_ctl_add(card, path->kcontrol);
506
			if (ret < 0) {
507 508 509
				dev_err(dapm->dev,
					"asoc: failed to add dapm kcontrol %s: %d\n",
					path->long_name, ret);
510
				kfree(wlist);
511 512 513 514
				kfree(path->long_name);
				path->long_name = NULL;
				return ret;
			}
515
			w->kcontrols[i] = path->kcontrol;
516 517 518 519 520 521
		}
	}
	return ret;
}

/* create new dapm mux control */
522
static int dapm_new_mux(struct snd_soc_dapm_widget *w)
523
{
524
	struct snd_soc_dapm_context *dapm = w->dapm;
525 526
	struct snd_soc_dapm_path *path = NULL;
	struct snd_kcontrol *kcontrol;
527
	struct snd_card *card = dapm->card->snd_card;
528
	const char *prefix;
529
	size_t prefix_len;
530
	int ret;
531
	struct snd_soc_dapm_widget_list *wlist;
532
	int shared, wlistentries;
533
	size_t wlistsize;
534
	char *name;
535

536 537 538 539
	if (w->num_kcontrols != 1) {
		dev_err(dapm->dev,
			"asoc: mux %s has incorrect number of controls\n",
			w->name);
540 541 542
		return -EINVAL;
	}

543
	shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0],
544 545 546 547 548 549 550 551
					 &kcontrol);
	if (kcontrol) {
		wlist = kcontrol->private_data;
		wlistentries = wlist->num_widgets + 1;
	} else {
		wlist = NULL;
		wlistentries = 1;
	}
552
	wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
553 554
		wlistentries * sizeof(struct snd_soc_dapm_widget *),
	wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
555 556 557 558 559
	if (wlist == NULL) {
		dev_err(dapm->dev,
			"asoc: can't allocate widget list for %s\n", w->name);
		return -ENOMEM;
	}
560 561
	wlist->num_widgets = wlistentries;
	wlist->widgets[wlistentries - 1] = w;
562

563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
	if (!kcontrol) {
		if (dapm->codec)
			prefix = dapm->codec->name_prefix;
		else
			prefix = NULL;

		if (shared) {
			name = w->kcontrol_news[0].name;
			prefix_len = 0;
		} else {
			name = w->name;
			if (prefix)
				prefix_len = strlen(prefix) + 1;
			else
				prefix_len = 0;
		}
579

580 581 582 583 584 585 586 587 588
		/*
		 * The control will get a prefix from the control creation
		 * process but we're also using the same prefix for widgets so
		 * cut the prefix off the front of the widget name.
		 */
		kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
					name + prefix_len, prefix);
		ret = snd_ctl_add(card, kcontrol);
		if (ret < 0) {
589 590
			dev_err(dapm->dev, "failed to add kcontrol %s: %d\n",
				w->name, ret);
591 592 593 594
			kfree(wlist);
			return ret;
		}
	}
L
Liam Girdwood 已提交
595

596
	kcontrol->private_data = wlist;
597

598 599
	w->kcontrols[0] = kcontrol;

600 601 602
	list_for_each_entry(path, &w->sources, list_sink)
		path->kcontrol = kcontrol;

603
	return 0;
604 605 606
}

/* create new dapm volume control */
607
static int dapm_new_pga(struct snd_soc_dapm_widget *w)
608
{
609
	if (w->num_kcontrols)
610 611
		dev_err(w->dapm->dev,
			"asoc: PGA controls not supported: '%s'\n", w->name);
612

613
	return 0;
614 615 616
}

/* reset 'walked' bit for each dapm path */
L
Liam Girdwood 已提交
617
static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
618 619 620
{
	struct snd_soc_dapm_path *p;

621
	list_for_each_entry(p, &dapm->card->paths, list)
622 623 624
		p->walked = 0;
}

625 626 627 628 629 630
/* We implement power down on suspend by checking the power state of
 * the ALSA card - when we are suspending the ALSA state for the card
 * is set to D3.
 */
static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
{
631
	int level = snd_power_get_state(widget->dapm->card->snd_card);
632

633
	switch (level) {
634 635
	case SNDRV_CTL_POWER_D3hot:
	case SNDRV_CTL_POWER_D3cold:
636
		if (widget->ignore_suspend)
637 638
			dev_dbg(widget->dapm->dev, "%s ignoring suspend\n",
				widget->name);
639
		return widget->ignore_suspend;
640 641 642 643 644
	default:
		return 1;
	}
}

645 646 647 648 649 650 651 652 653
/*
 * Recursively check for a completed path to an active or physically connected
 * output widget. Returns number of complete paths.
 */
static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
{
	struct snd_soc_dapm_path *path;
	int con = 0;

654 655
	DAPM_UPDATE_STAT(widget, path_checks);

656 657 658
	if (widget->id == snd_soc_dapm_supply)
		return 0;

659 660 661 662
	switch (widget->id) {
	case snd_soc_dapm_adc:
	case snd_soc_dapm_aif_out:
		if (widget->active)
663
			return snd_soc_dapm_suspend_check(widget);
664 665 666
	default:
		break;
	}
667 668 669 670

	if (widget->connected) {
		/* connected pin ? */
		if (widget->id == snd_soc_dapm_output && !widget->ext)
671
			return snd_soc_dapm_suspend_check(widget);
672 673 674

		/* connected jack or spk ? */
		if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
675
		    (widget->id == snd_soc_dapm_line && !list_empty(&widget->sources)))
676
			return snd_soc_dapm_suspend_check(widget);
677 678 679
	}

	list_for_each_entry(path, &widget->sinks, list_source) {
680 681 682
		if (path->weak)
			continue;

683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
		if (path->walked)
			continue;

		if (path->sink && path->connect) {
			path->walked = 1;
			con += is_connected_output_ep(path->sink);
		}
	}

	return con;
}

/*
 * Recursively check for a completed path to an active or physically connected
 * input widget. Returns number of complete paths.
 */
static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
{
	struct snd_soc_dapm_path *path;
	int con = 0;

704 705
	DAPM_UPDATE_STAT(widget, path_checks);

706 707 708
	if (widget->id == snd_soc_dapm_supply)
		return 0;

709
	/* active stream ? */
710 711 712 713
	switch (widget->id) {
	case snd_soc_dapm_dac:
	case snd_soc_dapm_aif_in:
		if (widget->active)
714
			return snd_soc_dapm_suspend_check(widget);
715 716 717
	default:
		break;
	}
718 719 720 721

	if (widget->connected) {
		/* connected pin ? */
		if (widget->id == snd_soc_dapm_input && !widget->ext)
722
			return snd_soc_dapm_suspend_check(widget);
723 724 725

		/* connected VMID/Bias for lower pops */
		if (widget->id == snd_soc_dapm_vmid)
726
			return snd_soc_dapm_suspend_check(widget);
727 728

		/* connected jack ? */
729 730
		if (widget->id == snd_soc_dapm_mic ||
		    (widget->id == snd_soc_dapm_line && !list_empty(&widget->sinks)))
731
			return snd_soc_dapm_suspend_check(widget);
732 733 734
	}

	list_for_each_entry(path, &widget->sources, list_sink) {
735 736 737
		if (path->weak)
			continue;

738 739 740 741 742 743 744 745 746 747 748 749
		if (path->walked)
			continue;

		if (path->source && path->connect) {
			path->walked = 1;
			con += is_connected_input_ep(path->source);
		}
	}

	return con;
}

750 751 752 753 754 755 756 757 758 759 760 761 762
/*
 * Handler for generic register modifier widget.
 */
int dapm_reg_event(struct snd_soc_dapm_widget *w,
		   struct snd_kcontrol *kcontrol, int event)
{
	unsigned int val;

	if (SND_SOC_DAPM_EVENT_ON(event))
		val = w->on_val;
	else
		val = w->off_val;

763
	soc_widget_update_bits(w, -(w->reg + 1),
764 765 766 767
			    w->mask << w->shift, val << w->shift);

	return 0;
}
768
EXPORT_SYMBOL_GPL(dapm_reg_event);
769

770 771 772 773 774 775
/* Generic check to see if a widget should be powered.
 */
static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
{
	int in, out;

776 777
	DAPM_UPDATE_STAT(w, power_checks);

778
	in = is_connected_input_ep(w);
L
Liam Girdwood 已提交
779
	dapm_clear_walk(w->dapm);
780
	out = is_connected_output_ep(w);
L
Liam Girdwood 已提交
781
	dapm_clear_walk(w->dapm);
782 783 784
	return out != 0 && in != 0;
}

785 786 787 788 789
/* Check to see if an ADC has power */
static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
{
	int in;

790 791
	DAPM_UPDATE_STAT(w, power_checks);

792 793
	if (w->active) {
		in = is_connected_input_ep(w);
L
Liam Girdwood 已提交
794
		dapm_clear_walk(w->dapm);
795 796 797 798 799 800 801 802 803 804 805
		return in != 0;
	} else {
		return dapm_generic_check_power(w);
	}
}

/* Check to see if a DAC has power */
static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
{
	int out;

806 807
	DAPM_UPDATE_STAT(w, power_checks);

808 809
	if (w->active) {
		out = is_connected_output_ep(w);
L
Liam Girdwood 已提交
810
		dapm_clear_walk(w->dapm);
811 812 813 814 815 816
		return out != 0;
	} else {
		return dapm_generic_check_power(w);
	}
}

817 818 819 820 821 822
/* Check to see if a power supply is needed */
static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
{
	struct snd_soc_dapm_path *path;
	int power = 0;

823 824
	DAPM_UPDATE_STAT(w, power_checks);

825 826
	/* Check if one of our outputs is connected */
	list_for_each_entry(path, &w->sinks, list_source) {
827 828 829
		if (path->weak)
			continue;

830 831 832 833
		if (path->connected &&
		    !path->connected(path->source, path->sink))
			continue;

834 835 836 837 838 839 840 841 842
		if (!path->sink)
			continue;

		if (path->sink->force) {
			power = 1;
			break;
		}

		if (path->sink->power_check &&
843 844 845 846 847 848
		    path->sink->power_check(path->sink)) {
			power = 1;
			break;
		}
	}

L
Liam Girdwood 已提交
849
	dapm_clear_walk(w->dapm);
850 851 852 853

	return power;
}

854 855
static int dapm_seq_compare(struct snd_soc_dapm_widget *a,
			    struct snd_soc_dapm_widget *b,
856
			    bool power_up)
857
{
858 859 860 861 862 863 864
	int *sort;

	if (power_up)
		sort = dapm_up_seq;
	else
		sort = dapm_down_seq;

865 866
	if (sort[a->id] != sort[b->id])
		return sort[a->id] - sort[b->id];
867 868 869 870 871 872
	if (a->subseq != b->subseq) {
		if (power_up)
			return a->subseq - b->subseq;
		else
			return b->subseq - a->subseq;
	}
873 874
	if (a->reg != b->reg)
		return a->reg - b->reg;
875 876
	if (a->dapm != b->dapm)
		return (unsigned long)a->dapm - (unsigned long)b->dapm;
877

878 879
	return 0;
}
880

881 882 883
/* Insert a widget in order into a DAPM power sequence. */
static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
			    struct list_head *list,
884
			    bool power_up)
885 886 887 888
{
	struct snd_soc_dapm_widget *w;

	list_for_each_entry(w, list, power_list)
889
		if (dapm_seq_compare(new_widget, w, power_up) < 0) {
890 891 892 893 894 895 896
			list_add_tail(&new_widget->power_list, &w->power_list);
			return;
		}

	list_add_tail(&new_widget->power_list, list);
}

897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
				 struct snd_soc_dapm_widget *w, int event)
{
	struct snd_soc_card *card = dapm->card;
	const char *ev_name;
	int power, ret;

	switch (event) {
	case SND_SOC_DAPM_PRE_PMU:
		ev_name = "PRE_PMU";
		power = 1;
		break;
	case SND_SOC_DAPM_POST_PMU:
		ev_name = "POST_PMU";
		power = 1;
		break;
	case SND_SOC_DAPM_PRE_PMD:
		ev_name = "PRE_PMD";
		power = 0;
		break;
	case SND_SOC_DAPM_POST_PMD:
		ev_name = "POST_PMD";
		power = 0;
		break;
	default:
		BUG();
		return;
	}

	if (w->power != power)
		return;

	if (w->event && (w->event_flags & event)) {
		pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n",
			w->name, ev_name);
M
Mark Brown 已提交
932
		trace_snd_soc_dapm_widget_event_start(w, event);
933
		ret = w->event(w, NULL, event);
M
Mark Brown 已提交
934
		trace_snd_soc_dapm_widget_event_done(w, event);
935 936 937 938 939 940
		if (ret < 0)
			pr_err("%s: %s event failed: %d\n",
			       ev_name, w->name, ret);
	}
}

941
/* Apply the coalesced changes from a DAPM sequence */
L
Liam Girdwood 已提交
942
static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
943
				   struct list_head *pending)
944
{
945
	struct snd_soc_card *card = dapm->card;
946 947
	struct snd_soc_dapm_widget *w;
	int reg, power;
948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
	unsigned int value = 0;
	unsigned int mask = 0;
	unsigned int cur_mask;

	reg = list_first_entry(pending, struct snd_soc_dapm_widget,
			       power_list)->reg;

	list_for_each_entry(w, pending, power_list) {
		cur_mask = 1 << w->shift;
		BUG_ON(reg != w->reg);

		if (w->invert)
			power = !w->power;
		else
			power = w->power;

		mask |= cur_mask;
		if (power)
			value |= cur_mask;

968
		pop_dbg(dapm->dev, card->pop_time,
969 970
			"pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
			w->name, reg, value, mask);
971

972 973 974
		/* Check for events */
		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU);
		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD);
975 976 977
	}

	if (reg >= 0) {
978 979 980 981 982 983
		/* Any widget will do, they should all be updating the
		 * same register.
		 */
		w = list_first_entry(pending, struct snd_soc_dapm_widget,
				     power_list);

984
		pop_dbg(dapm->dev, card->pop_time,
985
			"pop test : Applying 0x%x/0x%x to %x in %dms\n",
986 987
			value, mask, reg, card->pop_time);
		pop_wait(card->pop_time);
988
		soc_widget_update_bits(w, reg, mask, value);
989 990
	}

991
	list_for_each_entry(w, pending, power_list) {
992 993
		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU);
		dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD);
994
	}
995
}
996

997 998 999 1000 1001 1002 1003 1004
/* Apply a DAPM power sequence.
 *
 * We walk over a pre-sorted list of widgets to apply power to.  In
 * order to minimise the number of writes to the device required
 * multiple widgets will be updated in a single write where possible.
 * Currently anything that requires more than a single write is not
 * handled.
 */
L
Liam Girdwood 已提交
1005
static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
1006
			 struct list_head *list, int event, bool power_up)
1007 1008 1009 1010
{
	struct snd_soc_dapm_widget *w, *n;
	LIST_HEAD(pending);
	int cur_sort = -1;
1011
	int cur_subseq = -1;
1012
	int cur_reg = SND_SOC_NOPM;
1013
	struct snd_soc_dapm_context *cur_dapm = NULL;
1014
	int ret, i;
1015 1016 1017 1018 1019 1020
	int *sort;

	if (power_up)
		sort = dapm_up_seq;
	else
		sort = dapm_down_seq;
1021

1022 1023 1024 1025
	list_for_each_entry_safe(w, n, list, power_list) {
		ret = 0;

		/* Do we need to apply any queued changes? */
1026
		if (sort[w->id] != cur_sort || w->reg != cur_reg ||
1027
		    w->dapm != cur_dapm || w->subseq != cur_subseq) {
1028
			if (!list_empty(&pending))
1029
				dapm_seq_run_coalesced(cur_dapm, &pending);
1030

1031 1032 1033 1034
			if (cur_dapm && cur_dapm->seq_notifier) {
				for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
					if (sort[i] == cur_sort)
						cur_dapm->seq_notifier(cur_dapm,
1035 1036
								       i,
								       cur_subseq);
1037 1038
			}

1039 1040
			INIT_LIST_HEAD(&pending);
			cur_sort = -1;
1041
			cur_subseq = INT_MIN;
1042
			cur_reg = SND_SOC_NOPM;
1043
			cur_dapm = NULL;
1044 1045
		}

1046 1047 1048
		switch (w->id) {
		case snd_soc_dapm_pre:
			if (!w->event)
1049 1050
				list_for_each_entry_safe_continue(w, n, list,
								  power_list);
1051

1052
			if (event == SND_SOC_DAPM_STREAM_START)
1053 1054
				ret = w->event(w,
					       NULL, SND_SOC_DAPM_PRE_PMU);
1055
			else if (event == SND_SOC_DAPM_STREAM_STOP)
1056 1057 1058 1059 1060 1061
				ret = w->event(w,
					       NULL, SND_SOC_DAPM_PRE_PMD);
			break;

		case snd_soc_dapm_post:
			if (!w->event)
1062 1063
				list_for_each_entry_safe_continue(w, n, list,
								  power_list);
1064

1065
			if (event == SND_SOC_DAPM_STREAM_START)
1066 1067
				ret = w->event(w,
					       NULL, SND_SOC_DAPM_POST_PMU);
1068
			else if (event == SND_SOC_DAPM_STREAM_STOP)
1069 1070 1071 1072
				ret = w->event(w,
					       NULL, SND_SOC_DAPM_POST_PMD);
			break;

1073
		default:
1074 1075
			/* Queue it up for application */
			cur_sort = sort[w->id];
1076
			cur_subseq = w->subseq;
1077
			cur_reg = w->reg;
1078
			cur_dapm = w->dapm;
1079 1080
			list_move(&w->power_list, &pending);
			break;
1081
		}
1082 1083

		if (ret < 0)
1084 1085
			dev_err(w->dapm->dev,
				"Failed to apply widget power: %d\n", ret);
1086
	}
1087 1088

	if (!list_empty(&pending))
1089
		dapm_seq_run_coalesced(cur_dapm, &pending);
1090 1091 1092 1093 1094

	if (cur_dapm && cur_dapm->seq_notifier) {
		for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
			if (sort[i] == cur_sort)
				cur_dapm->seq_notifier(cur_dapm,
1095
						       i, cur_subseq);
1096
	}
1097 1098
}

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
{
	struct snd_soc_dapm_update *update = dapm->update;
	struct snd_soc_dapm_widget *w;
	int ret;

	if (!update)
		return;

	w = update->widget;

	if (w->event &&
	    (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
		ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
		if (ret != 0)
			pr_err("%s DAPM pre-event failed: %d\n",
			       w->name, ret);
	}

	ret = snd_soc_update_bits(w->codec, update->reg, update->mask,
				  update->val);
	if (ret < 0)
		pr_err("%s DAPM update failed: %d\n", w->name, ret);

	if (w->event &&
	    (w->event_flags & SND_SOC_DAPM_POST_REG)) {
		ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
		if (ret != 0)
			pr_err("%s DAPM post-event failed: %d\n",
			       w->name, ret);
	}
}

1132 1133 1134 1135 1136 1137 1138 1139
/* Async callback run prior to DAPM sequences - brings to _PREPARE if
 * they're changing state.
 */
static void dapm_pre_sequence_async(void *data, async_cookie_t cookie)
{
	struct snd_soc_dapm_context *d = data;
	int ret;

1140 1141 1142
	/* If we're off and we're not supposed to be go into STANDBY */
	if (d->bias_level == SND_SOC_BIAS_OFF &&
	    d->target_bias_level != SND_SOC_BIAS_OFF) {
1143 1144 1145 1146 1147 1148
		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
		if (ret != 0)
			dev_err(d->dev,
				"Failed to turn on bias: %d\n", ret);
	}

1149 1150
	/* Prepare for a STADDBY->ON or ON->STANDBY transition */
	if (d->bias_level != d->target_bias_level) {
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE);
		if (ret != 0)
			dev_err(d->dev,
				"Failed to prepare bias: %d\n", ret);
	}
}

/* Async callback run prior to DAPM sequences - brings to their final
 * state.
 */
static void dapm_post_sequence_async(void *data, async_cookie_t cookie)
{
	struct snd_soc_dapm_context *d = data;
	int ret;

	/* If we just powered the last thing off drop to standby bias */
1167 1168 1169
	if (d->bias_level == SND_SOC_BIAS_PREPARE &&
	    (d->target_bias_level == SND_SOC_BIAS_STANDBY ||
	     d->target_bias_level == SND_SOC_BIAS_OFF)) {
1170 1171 1172 1173 1174
		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY);
		if (ret != 0)
			dev_err(d->dev, "Failed to apply standby bias: %d\n",
				ret);
	}
1175

1176
	/* If we're in standby and can support bias off then do that */
1177 1178
	if (d->bias_level == SND_SOC_BIAS_STANDBY &&
	    d->target_bias_level == SND_SOC_BIAS_OFF) {
1179 1180 1181 1182 1183 1184
		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF);
		if (ret != 0)
			dev_err(d->dev, "Failed to turn off bias: %d\n", ret);
	}

	/* If we just powered up then move to active bias */
1185 1186
	if (d->bias_level == SND_SOC_BIAS_PREPARE &&
	    d->target_bias_level == SND_SOC_BIAS_ON) {
1187 1188 1189 1190 1191 1192
		ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON);
		if (ret != 0)
			dev_err(d->dev, "Failed to apply active bias: %d\n",
				ret);
	}
}
1193

1194 1195 1196 1197 1198 1199 1200 1201 1202
/*
 * Scan each dapm widget for complete audio path.
 * A complete path is a route that has valid endpoints i.e.:-
 *
 *  o DAC to output pin.
 *  o Input Pin to ADC.
 *  o Input pin to Output pin (bypass, sidetone)
 *  o DAC to ADC (loopback).
 */
L
Liam Girdwood 已提交
1203
static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
1204
{
1205
	struct snd_soc_card *card = dapm->card;
1206
	struct snd_soc_dapm_widget *w;
1207
	struct snd_soc_dapm_context *d;
1208 1209
	LIST_HEAD(up_list);
	LIST_HEAD(down_list);
1210
	LIST_HEAD(async_domain);
1211
	enum snd_soc_bias_level bias;
1212
	int power;
1213

M
Mark Brown 已提交
1214 1215
	trace_snd_soc_dapm_start(card);

1216 1217 1218 1219 1220 1221 1222 1223
	list_for_each_entry(d, &card->dapm_list, list) {
		if (d->n_widgets || d->codec == NULL) {
			if (d->idle_bias_off)
				d->target_bias_level = SND_SOC_BIAS_OFF;
			else
				d->target_bias_level = SND_SOC_BIAS_STANDBY;
		}
	}
1224

1225 1226
	memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));

1227 1228 1229
	/* Check which widgets we need to power and store them in
	 * lists indicating if they should be powered up or down.
	 */
1230
	list_for_each_entry(w, &card->widgets, list) {
1231 1232
		switch (w->id) {
		case snd_soc_dapm_pre:
1233
			dapm_seq_insert(w, &down_list, false);
1234 1235
			break;
		case snd_soc_dapm_post:
1236
			dapm_seq_insert(w, &up_list, true);
1237 1238 1239 1240 1241 1242
			break;

		default:
			if (!w->power_check)
				continue;

1243
			if (!w->force)
1244
				power = w->power_check(w);
1245 1246
			else
				power = 1;
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267

			if (power) {
				d = w->dapm;

				/* Supplies and micbiases only bring
				 * the context up to STANDBY as unless
				 * something else is active and
				 * passing audio they generally don't
				 * require full power.
				 */
				switch (w->id) {
				case snd_soc_dapm_supply:
				case snd_soc_dapm_micbias:
					if (d->target_bias_level < SND_SOC_BIAS_STANDBY)
						d->target_bias_level = SND_SOC_BIAS_STANDBY;
					break;
				default:
					d->target_bias_level = SND_SOC_BIAS_ON;
					break;
				}
			}
1268

1269 1270 1271
			if (w->power == power)
				continue;

M
Mark Brown 已提交
1272 1273
			trace_snd_soc_dapm_widget_power(w, power);

1274
			if (power)
1275
				dapm_seq_insert(w, &up_list, true);
1276
			else
1277
				dapm_seq_insert(w, &down_list, false);
1278 1279 1280 1281

			w->power = power;
			break;
		}
1282 1283
	}

1284 1285 1286
	/* If there are no DAPM widgets then try to figure out power from the
	 * event type.
	 */
1287
	if (!dapm->n_widgets) {
1288 1289 1290
		switch (event) {
		case SND_SOC_DAPM_STREAM_START:
		case SND_SOC_DAPM_STREAM_RESUME:
1291
			dapm->target_bias_level = SND_SOC_BIAS_ON;
1292
			break;
1293
		case SND_SOC_DAPM_STREAM_STOP:
1294 1295 1296 1297
			if (dapm->codec->active)
				dapm->target_bias_level = SND_SOC_BIAS_ON;
			else
				dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
1298
			break;
1299
		case SND_SOC_DAPM_STREAM_SUSPEND:
1300
			dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
1301
			break;
1302
		case SND_SOC_DAPM_STREAM_NOP:
1303
			dapm->target_bias_level = dapm->bias_level;
1304
			break;
1305 1306 1307 1308 1309
		default:
			break;
		}
	}

1310
	/* Force all contexts in the card to the same bias state */
1311
	bias = SND_SOC_BIAS_OFF;
1312
	list_for_each_entry(d, &card->dapm_list, list)
1313 1314
		if (d->target_bias_level > bias)
			bias = d->target_bias_level;
1315
	list_for_each_entry(d, &card->dapm_list, list)
1316
		d->target_bias_level = bias;
1317

1318
	trace_snd_soc_dapm_walk_done(card);
1319

1320 1321 1322 1323 1324
	/* Run all the bias changes in parallel */
	list_for_each_entry(d, &dapm->card->dapm_list, list)
		async_schedule_domain(dapm_pre_sequence_async, d,
					&async_domain);
	async_synchronize_full_domain(&async_domain);
1325

1326
	/* Power down widgets first; try to avoid amplifying pops. */
1327
	dapm_seq_run(dapm, &down_list, event, false);
1328

1329 1330
	dapm_widget_update(dapm);

1331
	/* Now power up. */
1332
	dapm_seq_run(dapm, &up_list, event, true);
1333

1334 1335 1336 1337 1338
	/* Run all the bias changes in parallel */
	list_for_each_entry(d, &dapm->card->dapm_list, list)
		async_schedule_domain(dapm_post_sequence_async, d,
					&async_domain);
	async_synchronize_full_domain(&async_domain);
1339

1340 1341
	pop_dbg(dapm->dev, card->pop_time,
		"DAPM sequencing finished, waiting %dms\n", card->pop_time);
1342
	pop_wait(card->pop_time);
1343

M
Mark Brown 已提交
1344 1345
	trace_snd_soc_dapm_done(card);

1346
	return 0;
1347 1348
}

1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
#ifdef CONFIG_DEBUG_FS
static int dapm_widget_power_open_file(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t dapm_widget_power_read_file(struct file *file,
					   char __user *user_buf,
					   size_t count, loff_t *ppos)
{
	struct snd_soc_dapm_widget *w = file->private_data;
	char *buf;
	int in, out;
	ssize_t ret;
	struct snd_soc_dapm_path *p = NULL;

	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	in = is_connected_input_ep(w);
L
Liam Girdwood 已提交
1371
	dapm_clear_walk(w->dapm);
1372
	out = is_connected_output_ep(w);
L
Liam Girdwood 已提交
1373
	dapm_clear_walk(w->dapm);
1374

1375
	ret = snprintf(buf, PAGE_SIZE, "%s: %s  in %d out %d",
1376 1377
		       w->name, w->power ? "On" : "Off", in, out);

1378 1379 1380 1381 1382 1383 1384
	if (w->reg >= 0)
		ret += snprintf(buf + ret, PAGE_SIZE - ret,
				" - R%d(0x%x) bit %d",
				w->reg, w->reg, w->shift);

	ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");

1385 1386 1387 1388
	if (w->sname)
		ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n",
				w->sname,
				w->active ? "active" : "inactive");
1389 1390

	list_for_each_entry(p, &w->sources, list_sink) {
1391 1392 1393
		if (p->connected && !p->connected(w, p->sink))
			continue;

1394 1395
		if (p->connect)
			ret += snprintf(buf + ret, PAGE_SIZE - ret,
1396
					" in  \"%s\" \"%s\"\n",
1397 1398 1399 1400
					p->name ? p->name : "static",
					p->source->name);
	}
	list_for_each_entry(p, &w->sinks, list_source) {
1401 1402 1403
		if (p->connected && !p->connected(w, p->sink))
			continue;

1404 1405
		if (p->connect)
			ret += snprintf(buf + ret, PAGE_SIZE - ret,
1406
					" out \"%s\" \"%s\"\n",
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
					p->name ? p->name : "static",
					p->sink->name);
	}

	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);

	kfree(buf);
	return ret;
}

static const struct file_operations dapm_widget_power_fops = {
	.open = dapm_widget_power_open_file,
	.read = dapm_widget_power_read_file,
1420
	.llseek = default_llseek,
1421 1422
};

1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
static int dapm_bias_open_file(struct inode *inode, struct file *file)
{
	file->private_data = inode->i_private;
	return 0;
}

static ssize_t dapm_bias_read_file(struct file *file, char __user *user_buf,
				   size_t count, loff_t *ppos)
{
	struct snd_soc_dapm_context *dapm = file->private_data;
	char *level;

	switch (dapm->bias_level) {
	case SND_SOC_BIAS_ON:
		level = "On\n";
		break;
	case SND_SOC_BIAS_PREPARE:
		level = "Prepare\n";
		break;
	case SND_SOC_BIAS_STANDBY:
		level = "Standby\n";
		break;
	case SND_SOC_BIAS_OFF:
		level = "Off\n";
		break;
	default:
		BUG();
		level = "Unknown\n";
		break;
	}

	return simple_read_from_buffer(user_buf, count, ppos, level,
				       strlen(level));
}

static const struct file_operations dapm_bias_fops = {
	.open = dapm_bias_open_file,
	.read = dapm_bias_read_file,
	.llseek = default_llseek,
};

1464 1465
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
	struct dentry *parent)
1466 1467 1468
{
	struct dentry *d;

1469 1470 1471 1472 1473
	dapm->debugfs_dapm = debugfs_create_dir("dapm", parent);

	if (!dapm->debugfs_dapm) {
		printk(KERN_WARNING
		       "Failed to create DAPM debugfs directory\n");
1474
		return;
1475
	}
1476

1477 1478 1479 1480 1481 1482
	d = debugfs_create_file("bias_level", 0444,
				dapm->debugfs_dapm, dapm,
				&dapm_bias_fops);
	if (!d)
		dev_warn(dapm->dev,
			 "ASoC: Failed to create bias level debugfs file\n");
1483
}
1484

1485 1486 1487 1488
static void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
{
	struct snd_soc_dapm_context *dapm = w->dapm;
	struct dentry *d;
1489

1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
	if (!dapm->debugfs_dapm || !w->name)
		return;

	d = debugfs_create_file(w->name, 0444,
				dapm->debugfs_dapm, w,
				&dapm_widget_power_fops);
	if (!d)
		dev_warn(w->dapm->dev,
			"ASoC: Failed to create %s debugfs file\n",
			w->name);
1500
}
1501

1502 1503 1504 1505 1506
static void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
{
	debugfs_remove_recursive(dapm->debugfs_dapm);
}

1507
#else
1508 1509
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
	struct dentry *parent)
1510 1511
{
}
1512 1513 1514 1515 1516

static inline void dapm_debugfs_add_widget(struct snd_soc_dapm_widget *w)
{
}

1517 1518 1519 1520
static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
{
}

1521 1522
#endif

1523
/* test and update the power status of a mux widget */
1524
static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
1525 1526
				 struct snd_kcontrol *kcontrol, int change,
				 int mux, struct soc_enum *e)
1527 1528 1529 1530
{
	struct snd_soc_dapm_path *path;
	int found = 0;

1531
	if (widget->id != snd_soc_dapm_mux &&
1532
	    widget->id != snd_soc_dapm_virt_mux &&
1533
	    widget->id != snd_soc_dapm_value_mux)
1534 1535
		return -ENODEV;

1536
	if (!change)
1537 1538 1539
		return 0;

	/* find dapm widget path assoc with kcontrol */
1540
	list_for_each_entry(path, &widget->dapm->card->paths, list) {
1541 1542 1543
		if (path->kcontrol != kcontrol)
			continue;

1544
		if (!path->name || !e->texts[mux])
1545 1546 1547 1548
			continue;

		found = 1;
		/* we now need to match the string in the enum to the path */
1549
		if (!(strcmp(path->name, e->texts[mux])))
1550 1551 1552 1553 1554
			path->connect = 1; /* new connection */
		else
			path->connect = 0; /* old connection must be powered down */
	}

1555
	if (found)
L
Liam Girdwood 已提交
1556
		dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
1557 1558 1559 1560

	return 0;
}

1561
/* test and update the power status of a mixer or switch widget */
1562
static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
1563
				   struct snd_kcontrol *kcontrol, int connect)
1564 1565 1566 1567
{
	struct snd_soc_dapm_path *path;
	int found = 0;

1568
	if (widget->id != snd_soc_dapm_mixer &&
1569
	    widget->id != snd_soc_dapm_mixer_named_ctl &&
1570
	    widget->id != snd_soc_dapm_switch)
1571 1572 1573
		return -ENODEV;

	/* find dapm widget path assoc with kcontrol */
1574
	list_for_each_entry(path, &widget->dapm->card->paths, list) {
1575 1576 1577 1578 1579
		if (path->kcontrol != kcontrol)
			continue;

		/* found, now check type */
		found = 1;
1580
		path->connect = connect;
1581 1582
	}

1583
	if (found)
L
Liam Girdwood 已提交
1584
		dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
1585 1586 1587 1588 1589 1590 1591 1592

	return 0;
}

/* show dapm widget status in sys fs */
static ssize_t dapm_widget_show(struct device *dev,
	struct device_attribute *attr, char *buf)
{
1593 1594 1595
	struct snd_soc_pcm_runtime *rtd =
			container_of(dev, struct snd_soc_pcm_runtime, dev);
	struct snd_soc_codec *codec =rtd->codec;
1596 1597 1598 1599
	struct snd_soc_dapm_widget *w;
	int count = 0;
	char *state = "not set";

1600 1601 1602
	list_for_each_entry(w, &codec->card->widgets, list) {
		if (w->dapm != &codec->dapm)
			continue;
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613

		/* only display widgets that burnm power */
		switch (w->id) {
		case snd_soc_dapm_hp:
		case snd_soc_dapm_mic:
		case snd_soc_dapm_spk:
		case snd_soc_dapm_line:
		case snd_soc_dapm_micbias:
		case snd_soc_dapm_dac:
		case snd_soc_dapm_adc:
		case snd_soc_dapm_pga:
1614
		case snd_soc_dapm_out_drv:
1615
		case snd_soc_dapm_mixer:
1616
		case snd_soc_dapm_mixer_named_ctl:
1617
		case snd_soc_dapm_supply:
1618 1619 1620 1621 1622 1623 1624 1625 1626
			if (w->name)
				count += sprintf(buf + count, "%s: %s\n",
					w->name, w->power ? "On":"Off");
		break;
		default:
		break;
		}
	}

L
Liam Girdwood 已提交
1627
	switch (codec->dapm.bias_level) {
1628 1629
	case SND_SOC_BIAS_ON:
		state = "On";
1630
		break;
1631 1632
	case SND_SOC_BIAS_PREPARE:
		state = "Prepare";
1633
		break;
1634 1635
	case SND_SOC_BIAS_STANDBY:
		state = "Standby";
1636
		break;
1637 1638
	case SND_SOC_BIAS_OFF:
		state = "Off";
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
		break;
	}
	count += sprintf(buf + count, "PM State: %s\n", state);

	return count;
}

static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);

int snd_soc_dapm_sys_add(struct device *dev)
{
1650
	return device_create_file(dev, &dev_attr_dapm_widget);
1651 1652 1653 1654
}

static void snd_soc_dapm_sys_remove(struct device *dev)
{
1655
	device_remove_file(dev, &dev_attr_dapm_widget);
1656 1657 1658
}

/* free all dapm widgets and resources */
L
Liam Girdwood 已提交
1659
static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
1660 1661 1662 1663
{
	struct snd_soc_dapm_widget *w, *next_w;
	struct snd_soc_dapm_path *p, *next_p;

1664 1665 1666
	list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) {
		if (w->dapm != dapm)
			continue;
1667
		list_del(&w->list);
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
		/*
		 * remove source and sink paths associated to this widget.
		 * While removing the path, remove reference to it from both
		 * source and sink widgets so that path is removed only once.
		 */
		list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
			list_del(&p->list_sink);
			list_del(&p->list_source);
			list_del(&p->list);
			kfree(p->long_name);
			kfree(p);
		}
		list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
			list_del(&p->list_sink);
			list_del(&p->list_source);
			list_del(&p->list);
			kfree(p->long_name);
			kfree(p);
		}
1687
		kfree(w->kcontrols);
1688
		kfree(w->name);
1689 1690 1691 1692
		kfree(w);
	}
}

1693 1694 1695
static struct snd_soc_dapm_widget *dapm_find_widget(
			struct snd_soc_dapm_context *dapm, const char *pin,
			bool search_other_contexts)
1696 1697
{
	struct snd_soc_dapm_widget *w;
1698
	struct snd_soc_dapm_widget *fallback = NULL;
1699

1700
	list_for_each_entry(w, &dapm->card->widgets, list) {
1701
		if (!strcmp(w->name, pin)) {
1702 1703 1704 1705
			if (w->dapm == dapm)
				return w;
			else
				fallback = w;
1706 1707 1708
		}
	}

1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722
	if (search_other_contexts)
		return fallback;

	return NULL;
}

static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
				const char *pin, int status)
{
	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);

	if (!w) {
		dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
		return -EINVAL;
1723 1724
	}

1725 1726 1727 1728 1729
	w->connected = status;
	if (status == 0)
		w->force = 0;

	return 0;
1730 1731
}

1732
/**
1733
 * snd_soc_dapm_sync - scan and power dapm paths
L
Liam Girdwood 已提交
1734
 * @dapm: DAPM context
1735 1736 1737 1738 1739 1740
 *
 * Walks all dapm audio paths and powers widgets according to their
 * stream or path usage.
 *
 * Returns 0 for success.
 */
L
Liam Girdwood 已提交
1741
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
1742
{
L
Liam Girdwood 已提交
1743
	return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
1744
}
1745
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
1746

L
Liam Girdwood 已提交
1747
static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
1748
				  const struct snd_soc_dapm_route *route)
1749 1750 1751
{
	struct snd_soc_dapm_path *path;
	struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
1752
	struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
1753
	const char *sink;
1754
	const char *control = route->control;
1755 1756 1757
	const char *source;
	char prefixed_sink[80];
	char prefixed_source[80];
1758 1759
	int ret = 0;

1760
	if (dapm->codec && dapm->codec->name_prefix) {
1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771
		snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
			 dapm->codec->name_prefix, route->sink);
		sink = prefixed_sink;
		snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
			 dapm->codec->name_prefix, route->source);
		source = prefixed_source;
	} else {
		sink = route->sink;
		source = route->source;
	}

1772 1773 1774 1775 1776
	/*
	 * find src and dest widgets over all widgets but favor a widget from
	 * current DAPM context
	 */
	list_for_each_entry(w, &dapm->card->widgets, list) {
1777
		if (!wsink && !(strcmp(w->name, sink))) {
1778 1779 1780
			wtsink = w;
			if (w->dapm == dapm)
				wsink = w;
1781 1782 1783
			continue;
		}
		if (!wsource && !(strcmp(w->name, source))) {
1784 1785 1786
			wtsource = w;
			if (w->dapm == dapm)
				wsource = w;
1787 1788
		}
	}
1789 1790 1791 1792 1793
	/* use widget from another DAPM context if not found from this */
	if (!wsink)
		wsink = wtsink;
	if (!wsource)
		wsource = wtsource;
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803

	if (wsource == NULL || wsink == NULL)
		return -ENODEV;

	path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
	if (!path)
		return -ENOMEM;

	path->source = wsource;
	path->sink = wsink;
1804
	path->connected = route->connected;
1805 1806 1807 1808 1809 1810 1811 1812
	INIT_LIST_HEAD(&path->list);
	INIT_LIST_HEAD(&path->list_source);
	INIT_LIST_HEAD(&path->list_sink);

	/* check for external widgets */
	if (wsink->id == snd_soc_dapm_input) {
		if (wsource->id == snd_soc_dapm_micbias ||
			wsource->id == snd_soc_dapm_mic ||
1813 1814
			wsource->id == snd_soc_dapm_line ||
			wsource->id == snd_soc_dapm_output)
1815 1816 1817 1818 1819
			wsink->ext = 1;
	}
	if (wsource->id == snd_soc_dapm_output) {
		if (wsink->id == snd_soc_dapm_spk ||
			wsink->id == snd_soc_dapm_hp ||
1820 1821
			wsink->id == snd_soc_dapm_line ||
			wsink->id == snd_soc_dapm_input)
1822 1823 1824 1825 1826
			wsource->ext = 1;
	}

	/* connect static paths */
	if (control == NULL) {
1827
		list_add(&path->list, &dapm->card->paths);
1828 1829 1830 1831 1832 1833 1834
		list_add(&path->list_sink, &wsink->sources);
		list_add(&path->list_source, &wsource->sinks);
		path->connect = 1;
		return 0;
	}

	/* connect dynamic paths */
1835
	switch (wsink->id) {
1836 1837 1838
	case snd_soc_dapm_adc:
	case snd_soc_dapm_dac:
	case snd_soc_dapm_pga:
1839
	case snd_soc_dapm_out_drv:
1840 1841 1842 1843 1844 1845
	case snd_soc_dapm_input:
	case snd_soc_dapm_output:
	case snd_soc_dapm_micbias:
	case snd_soc_dapm_vmid:
	case snd_soc_dapm_pre:
	case snd_soc_dapm_post:
1846
	case snd_soc_dapm_supply:
1847 1848
	case snd_soc_dapm_aif_in:
	case snd_soc_dapm_aif_out:
1849
		list_add(&path->list, &dapm->card->paths);
1850 1851 1852 1853 1854
		list_add(&path->list_sink, &wsink->sources);
		list_add(&path->list_source, &wsource->sinks);
		path->connect = 1;
		return 0;
	case snd_soc_dapm_mux:
1855
	case snd_soc_dapm_virt_mux:
1856
	case snd_soc_dapm_value_mux:
L
Liam Girdwood 已提交
1857
		ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
1858
			&wsink->kcontrol_news[0]);
1859 1860 1861 1862 1863
		if (ret != 0)
			goto err;
		break;
	case snd_soc_dapm_switch:
	case snd_soc_dapm_mixer:
1864
	case snd_soc_dapm_mixer_named_ctl:
L
Liam Girdwood 已提交
1865
		ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
1866 1867 1868 1869 1870 1871 1872
		if (ret != 0)
			goto err;
		break;
	case snd_soc_dapm_hp:
	case snd_soc_dapm_mic:
	case snd_soc_dapm_line:
	case snd_soc_dapm_spk:
1873
		list_add(&path->list, &dapm->card->paths);
1874 1875 1876 1877 1878 1879 1880 1881
		list_add(&path->list_sink, &wsink->sources);
		list_add(&path->list_source, &wsource->sinks);
		path->connect = 0;
		return 0;
	}
	return 0;

err:
1882 1883
	dev_warn(dapm->dev, "asoc: no dapm match for %s --> %s --> %s\n",
		 source, control, sink);
1884 1885 1886
	kfree(path);
	return ret;
}
1887 1888 1889

/**
 * snd_soc_dapm_add_routes - Add routes between DAPM widgets
L
Liam Girdwood 已提交
1890
 * @dapm: DAPM context
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900
 * @route: audio routes
 * @num: number of routes
 *
 * Connects 2 dapm widgets together via a named audio path. The sink is
 * the widget receiving the audio signal, whilst the source is the sender
 * of the audio signal.
 *
 * Returns 0 for success else error. On error all resources can be freed
 * with a call to snd_soc_card_free().
 */
L
Liam Girdwood 已提交
1901
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
1902 1903 1904 1905 1906
			    const struct snd_soc_dapm_route *route, int num)
{
	int i, ret;

	for (i = 0; i < num; i++) {
L
Liam Girdwood 已提交
1907
		ret = snd_soc_dapm_add_route(dapm, route);
1908
		if (ret < 0) {
1909 1910
			dev_err(dapm->dev, "Failed to add route %s->%s\n",
				route->source, route->sink);
1911 1912 1913 1914 1915 1916 1917 1918 1919
			return ret;
		}
		route++;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);

1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997
static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm,
				   const struct snd_soc_dapm_route *route)
{
	struct snd_soc_dapm_widget *source = dapm_find_widget(dapm,
							      route->source,
							      true);
	struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm,
							    route->sink,
							    true);
	struct snd_soc_dapm_path *path;
	int count = 0;

	if (!source) {
		dev_err(dapm->dev, "Unable to find source %s for weak route\n",
			route->source);
		return -ENODEV;
	}

	if (!sink) {
		dev_err(dapm->dev, "Unable to find sink %s for weak route\n",
			route->sink);
		return -ENODEV;
	}

	if (route->control || route->connected)
		dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n",
			 route->source, route->sink);

	list_for_each_entry(path, &source->sinks, list_source) {
		if (path->sink == sink) {
			path->weak = 1;
			count++;
		}
	}

	if (count == 0)
		dev_err(dapm->dev, "No path found for weak route %s->%s\n",
			route->source, route->sink);
	if (count > 1)
		dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n",
			 count, route->source, route->sink);

	return 0;
}

/**
 * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak
 * @dapm: DAPM context
 * @route: audio routes
 * @num: number of routes
 *
 * Mark existing routes matching those specified in the passed array
 * as being weak, meaning that they are ignored for the purpose of
 * power decisions.  The main intended use case is for sidetone paths
 * which couple audio between other independent paths if they are both
 * active in order to make the combination work better at the user
 * level but which aren't intended to be "used".
 *
 * Note that CODEC drivers should not use this as sidetone type paths
 * can frequently also be used as bypass paths.
 */
int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
			     const struct snd_soc_dapm_route *route, int num)
{
	int i, err;
	int ret = 0;

	for (i = 0; i < num; i++) {
		err = snd_soc_dapm_weak_route(dapm, route);
		if (err)
			ret = err;
		route++;
	}

	return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);

1998 1999
/**
 * snd_soc_dapm_new_widgets - add new dapm widgets
L
Liam Girdwood 已提交
2000
 * @dapm: DAPM context
2001 2002 2003 2004 2005
 *
 * Checks the codec for any new dapm widgets and creates them if found.
 *
 * Returns 0 for success.
 */
L
Liam Girdwood 已提交
2006
int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
2007 2008
{
	struct snd_soc_dapm_widget *w;
2009
	unsigned int val;
2010

2011
	list_for_each_entry(w, &dapm->card->widgets, list)
2012 2013 2014 2015
	{
		if (w->new)
			continue;

2016 2017 2018 2019 2020 2021 2022 2023
		if (w->num_kcontrols) {
			w->kcontrols = kzalloc(w->num_kcontrols *
						sizeof(struct snd_kcontrol *),
						GFP_KERNEL);
			if (!w->kcontrols)
				return -ENOMEM;
		}

2024 2025 2026
		switch(w->id) {
		case snd_soc_dapm_switch:
		case snd_soc_dapm_mixer:
2027
		case snd_soc_dapm_mixer_named_ctl:
2028
			w->power_check = dapm_generic_check_power;
2029
			dapm_new_mixer(w);
2030 2031
			break;
		case snd_soc_dapm_mux:
2032
		case snd_soc_dapm_virt_mux:
P
Peter Ujfalusi 已提交
2033
		case snd_soc_dapm_value_mux:
2034
			w->power_check = dapm_generic_check_power;
2035
			dapm_new_mux(w);
2036 2037
			break;
		case snd_soc_dapm_adc:
2038
		case snd_soc_dapm_aif_out:
2039 2040
			w->power_check = dapm_adc_check_power;
			break;
2041
		case snd_soc_dapm_dac:
2042
		case snd_soc_dapm_aif_in:
2043 2044
			w->power_check = dapm_dac_check_power;
			break;
2045
		case snd_soc_dapm_pga:
2046
		case snd_soc_dapm_out_drv:
2047
			w->power_check = dapm_generic_check_power;
2048
			dapm_new_pga(w);
2049 2050 2051 2052 2053 2054 2055 2056
			break;
		case snd_soc_dapm_input:
		case snd_soc_dapm_output:
		case snd_soc_dapm_micbias:
		case snd_soc_dapm_spk:
		case snd_soc_dapm_hp:
		case snd_soc_dapm_mic:
		case snd_soc_dapm_line:
2057 2058
			w->power_check = dapm_generic_check_power;
			break;
2059 2060
		case snd_soc_dapm_supply:
			w->power_check = dapm_supply_check_power;
2061 2062 2063 2064 2065
		case snd_soc_dapm_vmid:
		case snd_soc_dapm_pre:
		case snd_soc_dapm_post:
			break;
		}
2066 2067 2068

		/* Read the initial power state from the device */
		if (w->reg >= 0) {
2069
			val = soc_widget_read(w, w->reg);
2070 2071 2072 2073 2074 2075 2076 2077
			val &= 1 << w->shift;
			if (w->invert)
				val = !val;

			if (val)
				w->power = 1;
		}

2078
		w->new = 1;
2079 2080

		dapm_debugfs_add_widget(w);
2081 2082
	}

L
Liam Girdwood 已提交
2083
	dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
2084 2085 2086 2087 2088 2089 2090
	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);

/**
 * snd_soc_dapm_get_volsw - dapm mixer get callback
 * @kcontrol: mixer control
M
Mark Brown 已提交
2091
 * @ucontrol: control element information
2092 2093 2094 2095 2096 2097 2098 2099
 *
 * Callback to get the value of a dapm mixer control.
 *
 * Returns 0 for success.
 */
int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
2100 2101
	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2102 2103
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
2104 2105 2106
	unsigned int reg = mc->reg;
	unsigned int shift = mc->shift;
	unsigned int rshift = mc->rshift;
2107
	int max = mc->max;
2108 2109
	unsigned int invert = mc->invert;
	unsigned int mask = (1 << fls(max)) - 1;
2110 2111 2112 2113 2114 2115 2116 2117

	ucontrol->value.integer.value[0] =
		(snd_soc_read(widget->codec, reg) >> shift) & mask;
	if (shift != rshift)
		ucontrol->value.integer.value[1] =
			(snd_soc_read(widget->codec, reg) >> rshift) & mask;
	if (invert) {
		ucontrol->value.integer.value[0] =
P
Philipp Zabel 已提交
2118
			max - ucontrol->value.integer.value[0];
2119 2120
		if (shift != rshift)
			ucontrol->value.integer.value[1] =
P
Philipp Zabel 已提交
2121
				max - ucontrol->value.integer.value[1];
2122 2123 2124 2125 2126 2127 2128 2129 2130
	}

	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);

/**
 * snd_soc_dapm_put_volsw - dapm mixer set callback
 * @kcontrol: mixer control
M
Mark Brown 已提交
2131
 * @ucontrol: control element information
2132 2133 2134 2135 2136 2137 2138 2139
 *
 * Callback to set the value of a dapm mixer control.
 *
 * Returns 0 for success.
 */
int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
2140 2141 2142
	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
	struct snd_soc_codec *codec = widget->codec;
2143 2144
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
2145 2146
	unsigned int reg = mc->reg;
	unsigned int shift = mc->shift;
2147
	int max = mc->max;
2148 2149
	unsigned int mask = (1 << fls(max)) - 1;
	unsigned int invert = mc->invert;
2150
	unsigned int val;
2151 2152
	int connect, change;
	struct snd_soc_dapm_update update;
2153
	int wi;
2154 2155 2156 2157

	val = (ucontrol->value.integer.value[0] & mask);

	if (invert)
P
Philipp Zabel 已提交
2158
		val = max - val;
2159
	mask = mask << shift;
2160 2161
	val = val << shift;

2162 2163 2164 2165 2166 2167 2168 2169
	if (val)
		/* new connection */
		connect = invert ? 0 : 1;
	else
		/* old connection must be powered down */
		connect = invert ? 1 : 0;

	mutex_lock(&codec->mutex);
2170

2171
	change = snd_soc_test_bits(widget->codec, reg, mask, val);
2172
	if (change) {
2173 2174
		for (wi = 0; wi < wlist->num_widgets; wi++) {
			widget = wlist->widgets[wi];
2175

2176
			widget->value = val;
2177

2178 2179 2180 2181 2182 2183
			update.kcontrol = kcontrol;
			update.widget = widget;
			update.reg = reg;
			update.mask = mask;
			update.val = val;
			widget->dapm->update = &update;
2184

2185 2186 2187 2188
			dapm_mixer_update_power(widget, kcontrol, connect);

			widget->dapm->update = NULL;
		}
2189 2190
	}

2191
	mutex_unlock(&codec->mutex);
2192
	return 0;
2193 2194 2195 2196 2197 2198
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);

/**
 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
 * @kcontrol: mixer control
M
Mark Brown 已提交
2199
 * @ucontrol: control element information
2200 2201 2202 2203 2204 2205 2206 2207
 *
 * Callback to get the value of a dapm enumerated double mixer control.
 *
 * Returns 0 for success.
 */
int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
2208 2209
	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2210
	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
2211
	unsigned int val, bitmask;
2212

2213
	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227
		;
	val = snd_soc_read(widget->codec, e->reg);
	ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
	if (e->shift_l != e->shift_r)
		ucontrol->value.enumerated.item[1] =
			(val >> e->shift_r) & (bitmask - 1);

	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);

/**
 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
 * @kcontrol: mixer control
M
Mark Brown 已提交
2228
 * @ucontrol: control element information
2229 2230 2231 2232 2233 2234 2235 2236
 *
 * Callback to set the value of a dapm enumerated double mixer control.
 *
 * Returns 0 for success.
 */
int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
2237 2238 2239
	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
	struct snd_soc_codec *codec = widget->codec;
2240
	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
2241
	unsigned int val, mux, change;
2242
	unsigned int mask, bitmask;
2243
	struct snd_soc_dapm_update update;
2244
	int wi;
2245

2246
	for (bitmask = 1; bitmask < e->max; bitmask <<= 1)
2247
		;
2248
	if (ucontrol->value.enumerated.item[0] > e->max - 1)
2249 2250 2251 2252 2253
		return -EINVAL;
	mux = ucontrol->value.enumerated.item[0];
	val = mux << e->shift_l;
	mask = (bitmask - 1) << e->shift_l;
	if (e->shift_l != e->shift_r) {
2254
		if (ucontrol->value.enumerated.item[1] > e->max - 1)
2255 2256 2257 2258 2259
			return -EINVAL;
		val |= ucontrol->value.enumerated.item[1] << e->shift_r;
		mask |= (bitmask - 1) << e->shift_r;
	}

2260 2261
	mutex_lock(&codec->mutex);

2262
	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
2263 2264 2265 2266 2267
	if (change) {
		for (wi = 0; wi < wlist->num_widgets; wi++) {
			widget = wlist->widgets[wi];

			widget->value = val;
2268

2269 2270 2271 2272 2273 2274
			update.kcontrol = kcontrol;
			update.widget = widget;
			update.reg = e->reg;
			update.mask = mask;
			update.val = val;
			widget->dapm->update = &update;
2275

2276
			dapm_mux_update_power(widget, kcontrol, change, mux, e);
2277

2278 2279 2280
			widget->dapm->update = NULL;
		}
	}
2281

2282
	mutex_unlock(&codec->mutex);
2283
	return change;
2284 2285 2286
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);

2287 2288 2289 2290 2291 2292 2293 2294 2295 2296
/**
 * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux
 * @kcontrol: mixer control
 * @ucontrol: control element information
 *
 * Returns 0 for success.
 */
int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
{
2297 2298
	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315

	ucontrol->value.enumerated.item[0] = widget->value;

	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);

/**
 * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux
 * @kcontrol: mixer control
 * @ucontrol: control element information
 *
 * Returns 0 for success.
 */
int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
			       struct snd_ctl_elem_value *ucontrol)
{
2316 2317 2318
	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
	struct snd_soc_codec *codec = widget->codec;
2319 2320 2321 2322
	struct soc_enum *e =
		(struct soc_enum *)kcontrol->private_value;
	int change;
	int ret = 0;
2323
	int wi;
2324 2325 2326 2327

	if (ucontrol->value.enumerated.item[0] >= e->max)
		return -EINVAL;

2328
	mutex_lock(&codec->mutex);
2329 2330

	change = widget->value != ucontrol->value.enumerated.item[0];
2331 2332 2333 2334 2335 2336 2337 2338 2339 2340
	if (change) {
		for (wi = 0; wi < wlist->num_widgets; wi++) {
			widget = wlist->widgets[wi];

			widget->value = ucontrol->value.enumerated.item[0];

			dapm_mux_update_power(widget, kcontrol, change,
					      widget->value, e);
		}
	}
2341

2342
	mutex_unlock(&codec->mutex);
2343 2344 2345 2346
	return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);

P
Peter Ujfalusi 已提交
2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362
/**
 * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get
 *					callback
 * @kcontrol: mixer control
 * @ucontrol: control element information
 *
 * Callback to get the value of a dapm semi enumerated double mixer control.
 *
 * Semi enumerated mixer: the enumerated items are referred as values. Can be
 * used for handling bitfield coded enumeration for example.
 *
 * Returns 0 for success.
 */
int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
2363 2364
	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
2365
	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
2366
	unsigned int reg_val, val, mux;
P
Peter Ujfalusi 已提交
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403

	reg_val = snd_soc_read(widget->codec, e->reg);
	val = (reg_val >> e->shift_l) & e->mask;
	for (mux = 0; mux < e->max; mux++) {
		if (val == e->values[mux])
			break;
	}
	ucontrol->value.enumerated.item[0] = mux;
	if (e->shift_l != e->shift_r) {
		val = (reg_val >> e->shift_r) & e->mask;
		for (mux = 0; mux < e->max; mux++) {
			if (val == e->values[mux])
				break;
		}
		ucontrol->value.enumerated.item[1] = mux;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);

/**
 * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set
 *					callback
 * @kcontrol: mixer control
 * @ucontrol: control element information
 *
 * Callback to set the value of a dapm semi enumerated double mixer control.
 *
 * Semi enumerated mixer: the enumerated items are referred as values. Can be
 * used for handling bitfield coded enumeration for example.
 *
 * Returns 0 for success.
 */
int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
	struct snd_ctl_elem_value *ucontrol)
{
2404 2405 2406
	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
	struct snd_soc_codec *codec = widget->codec;
2407
	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
2408
	unsigned int val, mux, change;
2409
	unsigned int mask;
2410
	struct snd_soc_dapm_update update;
2411
	int wi;
P
Peter Ujfalusi 已提交
2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424

	if (ucontrol->value.enumerated.item[0] > e->max - 1)
		return -EINVAL;
	mux = ucontrol->value.enumerated.item[0];
	val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l;
	mask = e->mask << e->shift_l;
	if (e->shift_l != e->shift_r) {
		if (ucontrol->value.enumerated.item[1] > e->max - 1)
			return -EINVAL;
		val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r;
		mask |= e->mask << e->shift_r;
	}

2425 2426
	mutex_lock(&codec->mutex);

2427
	change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
2428 2429 2430
	if (change) {
		for (wi = 0; wi < wlist->num_widgets; wi++) {
			widget = wlist->widgets[wi];
2431

2432
			widget->value = val;
2433

2434 2435 2436 2437 2438 2439
			update.kcontrol = kcontrol;
			update.widget = widget;
			update.reg = e->reg;
			update.mask = mask;
			update.val = val;
			widget->dapm->update = &update;
2440

2441 2442 2443 2444 2445
			dapm_mux_update_power(widget, kcontrol, change, mux, e);

			widget->dapm->update = NULL;
		}
	}
P
Peter Ujfalusi 已提交
2446

2447
	mutex_unlock(&codec->mutex);
2448
	return change;
P
Peter Ujfalusi 已提交
2449 2450 2451
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);

2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486
/**
 * snd_soc_dapm_info_pin_switch - Info for a pin switch
 *
 * @kcontrol: mixer control
 * @uinfo: control element information
 *
 * Callback to provide information about a pin switch control.
 */
int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol,
				 struct snd_ctl_elem_info *uinfo)
{
	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
	uinfo->count = 1;
	uinfo->value.integer.min = 0;
	uinfo->value.integer.max = 1;

	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_info_pin_switch);

/**
 * snd_soc_dapm_get_pin_switch - Get information for a pin switch
 *
 * @kcontrol: mixer control
 * @ucontrol: Value
 */
int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
	const char *pin = (const char *)kcontrol->private_value;

	mutex_lock(&codec->mutex);

	ucontrol->value.integer.value[0] =
L
Liam Girdwood 已提交
2487
		snd_soc_dapm_get_pin_status(&codec->dapm, pin);
2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509

	mutex_unlock(&codec->mutex);

	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_switch);

/**
 * snd_soc_dapm_put_pin_switch - Set information for a pin switch
 *
 * @kcontrol: mixer control
 * @ucontrol: Value
 */
int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
	const char *pin = (const char *)kcontrol->private_value;

	mutex_lock(&codec->mutex);

	if (ucontrol->value.integer.value[0])
L
Liam Girdwood 已提交
2510
		snd_soc_dapm_enable_pin(&codec->dapm, pin);
2511
	else
L
Liam Girdwood 已提交
2512
		snd_soc_dapm_disable_pin(&codec->dapm, pin);
2513

L
Liam Girdwood 已提交
2514
	snd_soc_dapm_sync(&codec->dapm);
2515 2516 2517 2518 2519 2520 2521

	mutex_unlock(&codec->mutex);

	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);

2522 2523
/**
 * snd_soc_dapm_new_control - create new dapm control
L
Liam Girdwood 已提交
2524
 * @dapm: DAPM context
2525 2526 2527 2528 2529 2530
 * @widget: widget template
 *
 * Creates a new dapm control based upon the template.
 *
 * Returns 0 for success else error.
 */
L
Liam Girdwood 已提交
2531
int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
2532 2533 2534
	const struct snd_soc_dapm_widget *widget)
{
	struct snd_soc_dapm_widget *w;
2535
	size_t name_len;
2536 2537 2538 2539

	if ((w = dapm_cnew_widget(widget)) == NULL)
		return -ENOMEM;

2540
	name_len = strlen(widget->name) + 1;
2541
	if (dapm->codec && dapm->codec->name_prefix)
2542 2543 2544 2545 2546 2547
		name_len += 1 + strlen(dapm->codec->name_prefix);
	w->name = kmalloc(name_len, GFP_KERNEL);
	if (w->name == NULL) {
		kfree(w);
		return -ENOMEM;
	}
2548
	if (dapm->codec && dapm->codec->name_prefix)
2549 2550 2551 2552 2553
		snprintf(w->name, name_len, "%s %s",
			dapm->codec->name_prefix, widget->name);
	else
		snprintf(w->name, name_len, "%s", widget->name);

2554
	dapm->n_widgets++;
L
Liam Girdwood 已提交
2555 2556
	w->dapm = dapm;
	w->codec = dapm->codec;
2557
	w->platform = dapm->platform;
2558 2559 2560
	INIT_LIST_HEAD(&w->sources);
	INIT_LIST_HEAD(&w->sinks);
	INIT_LIST_HEAD(&w->list);
2561
	list_add(&w->list, &dapm->card->widgets);
2562 2563 2564 2565 2566 2567 2568

	/* machine layer set ups unconnected pins and insertions */
	w->connected = 1;
	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);

2569 2570
/**
 * snd_soc_dapm_new_controls - create new dapm controls
L
Liam Girdwood 已提交
2571
 * @dapm: DAPM context
2572 2573 2574 2575 2576 2577 2578
 * @widget: widget array
 * @num: number of widgets
 *
 * Creates new DAPM controls based upon the templates.
 *
 * Returns 0 for success else error.
 */
L
Liam Girdwood 已提交
2579
int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
2580 2581 2582 2583 2584 2585
	const struct snd_soc_dapm_widget *widget,
	int num)
{
	int i, ret;

	for (i = 0; i < num; i++) {
L
Liam Girdwood 已提交
2586
		ret = snd_soc_dapm_new_control(dapm, widget);
2587
		if (ret < 0) {
2588 2589 2590
			dev_err(dapm->dev,
				"ASoC: Failed to create DAPM control %s: %d\n",
				widget->name, ret);
2591
			return ret;
2592
		}
2593 2594 2595 2596 2597 2598
		widget++;
	}
	return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);

L
Liam Girdwood 已提交
2599
static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
2600
	const char *stream, int event)
2601 2602 2603
{
	struct snd_soc_dapm_widget *w;

2604
	list_for_each_entry(w, &dapm->card->widgets, list)
2605
	{
2606
		if (!w->sname || w->dapm != dapm)
2607
			continue;
2608
		dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n",
2609
			w->name, w->sname, stream, event);
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626
		if (strstr(w->sname, stream)) {
			switch(event) {
			case SND_SOC_DAPM_STREAM_START:
				w->active = 1;
				break;
			case SND_SOC_DAPM_STREAM_STOP:
				w->active = 0;
				break;
			case SND_SOC_DAPM_STREAM_SUSPEND:
			case SND_SOC_DAPM_STREAM_RESUME:
			case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
			case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
				break;
			}
		}
	}

L
Liam Girdwood 已提交
2627
	dapm_power_widgets(dapm, event);
2628 2629 2630 2631

	/* do we need to notify any clients that DAPM stream is complete */
	if (dapm->stream_event)
		dapm->stream_event(dapm, event);
L
Liam Girdwood 已提交
2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654
}

/**
 * snd_soc_dapm_stream_event - send a stream event to the dapm core
 * @rtd: PCM runtime data
 * @stream: stream name
 * @event: stream event
 *
 * Sends a stream event to the dapm core. The core then makes any
 * necessary widget power changes.
 *
 * Returns 0 for success else error.
 */
int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
	const char *stream, int event)
{
	struct snd_soc_codec *codec = rtd->codec;

	if (stream == NULL)
		return 0;

	mutex_lock(&codec->mutex);
	soc_dapm_stream_event(&codec->dapm, stream, event);
2655
	mutex_unlock(&codec->mutex);
2656 2657 2658 2659
	return 0;
}

/**
2660
 * snd_soc_dapm_enable_pin - enable pin.
L
Liam Girdwood 已提交
2661
 * @dapm: DAPM context
2662
 * @pin: pin name
2663
 *
M
Mark Brown 已提交
2664
 * Enables input/output pin and its parents or children widgets iff there is
2665 2666 2667
 * a valid audio route and active audio stream.
 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
 * do any widget power switching.
2668
 */
L
Liam Girdwood 已提交
2669
int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin)
2670
{
L
Liam Girdwood 已提交
2671
	return snd_soc_dapm_set_pin(dapm, pin, 1);
2672 2673
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
2674

2675 2676
/**
 * snd_soc_dapm_force_enable_pin - force a pin to be enabled
L
Liam Girdwood 已提交
2677
 * @dapm: DAPM context
2678 2679 2680 2681 2682 2683 2684 2685 2686
 * @pin: pin name
 *
 * Enables input/output pin regardless of any other state.  This is
 * intended for use with microphone bias supplies used in microphone
 * jack detection.
 *
 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
 * do any widget power switching.
 */
L
Liam Girdwood 已提交
2687 2688
int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
				  const char *pin)
2689
{
2690
	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
2691

2692 2693 2694
	if (!w) {
		dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
		return -EINVAL;
2695 2696
	}

2697 2698 2699
	dev_dbg(w->dapm->dev, "dapm: force enable pin %s\n", pin);
	w->connected = 1;
	w->force = 1;
2700

2701
	return 0;
2702 2703 2704
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin);

2705 2706
/**
 * snd_soc_dapm_disable_pin - disable pin.
L
Liam Girdwood 已提交
2707
 * @dapm: DAPM context
2708 2709
 * @pin: pin name
 *
M
Mark Brown 已提交
2710
 * Disables input/output pin and its parents or children widgets.
2711 2712 2713
 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
 * do any widget power switching.
 */
L
Liam Girdwood 已提交
2714 2715
int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
			     const char *pin)
2716
{
L
Liam Girdwood 已提交
2717
	return snd_soc_dapm_set_pin(dapm, pin, 0);
2718
}
2719
EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
2720

2721 2722
/**
 * snd_soc_dapm_nc_pin - permanently disable pin.
L
Liam Girdwood 已提交
2723
 * @dapm: DAPM context
2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734
 * @pin: pin name
 *
 * Marks the specified pin as being not connected, disabling it along
 * any parent or child widgets.  At present this is identical to
 * snd_soc_dapm_disable_pin() but in future it will be extended to do
 * additional things such as disabling controls which only affect
 * paths through the pin.
 *
 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
 * do any widget power switching.
 */
L
Liam Girdwood 已提交
2735
int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin)
2736
{
L
Liam Girdwood 已提交
2737
	return snd_soc_dapm_set_pin(dapm, pin, 0);
2738 2739 2740
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin);

2741
/**
2742
 * snd_soc_dapm_get_pin_status - get audio pin status
L
Liam Girdwood 已提交
2743
 * @dapm: DAPM context
2744
 * @pin: audio signal pin endpoint (or start point)
2745
 *
2746
 * Get audio pin status - connected or disconnected.
2747
 *
2748
 * Returns 1 for connected otherwise 0.
2749
 */
L
Liam Girdwood 已提交
2750 2751
int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
				const char *pin)
2752
{
2753
	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
2754

2755 2756
	if (w)
		return w->connected;
2757

2758 2759
	return 0;
}
2760
EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
2761

2762 2763
/**
 * snd_soc_dapm_ignore_suspend - ignore suspend status for DAPM endpoint
L
Liam Girdwood 已提交
2764
 * @dapm: DAPM context
2765 2766 2767 2768 2769 2770 2771 2772
 * @pin: audio signal pin endpoint (or start point)
 *
 * Mark the given endpoint or pin as ignoring suspend.  When the
 * system is disabled a path between two endpoints flagged as ignoring
 * suspend will not be disabled.  The path must already be enabled via
 * normal means at suspend time, it will not be turned on if it was not
 * already enabled.
 */
L
Liam Girdwood 已提交
2773 2774
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
				const char *pin)
2775
{
2776
	struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, false);
2777

2778 2779 2780
	if (!w) {
		dev_err(dapm->dev, "dapm: unknown pin %s\n", pin);
		return -EINVAL;
2781 2782
	}

2783 2784 2785
	w->ignore_suspend = 1;

	return 0;
2786 2787 2788
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);

2789 2790
/**
 * snd_soc_dapm_free - free dapm resources
2791
 * @dapm: DAPM context
2792 2793 2794
 *
 * Free all dapm widgets and resources.
 */
L
Liam Girdwood 已提交
2795
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
2796
{
L
Liam Girdwood 已提交
2797
	snd_soc_dapm_sys_remove(dapm->dev);
2798
	dapm_debugfs_cleanup(dapm);
L
Liam Girdwood 已提交
2799
	dapm_free_widgets(dapm);
2800
	list_del(&dapm->list);
2801 2802 2803
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_free);

L
Liam Girdwood 已提交
2804
static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
M
Mark Brown 已提交
2805 2806 2807 2808 2809
{
	struct snd_soc_dapm_widget *w;
	LIST_HEAD(down_list);
	int powerdown = 0;

2810 2811 2812
	list_for_each_entry(w, &dapm->card->widgets, list) {
		if (w->dapm != dapm)
			continue;
M
Mark Brown 已提交
2813
		if (w->power) {
2814
			dapm_seq_insert(w, &down_list, false);
2815
			w->power = 0;
M
Mark Brown 已提交
2816 2817 2818 2819 2820 2821 2822 2823
			powerdown = 1;
		}
	}

	/* If there were no widgets to power down we're already in
	 * standby.
	 */
	if (powerdown) {
2824
		snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE);
2825
		dapm_seq_run(dapm, &down_list, 0, false);
2826
		snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY);
M
Mark Brown 已提交
2827
	}
2828 2829 2830 2831 2832 2833 2834 2835 2836
}

/*
 * snd_soc_dapm_shutdown - callback for system shutdown
 */
void snd_soc_dapm_shutdown(struct snd_soc_card *card)
{
	struct snd_soc_codec *codec;

L
Liam Girdwood 已提交
2837 2838
	list_for_each_entry(codec, &card->codec_dev_list, list) {
		soc_dapm_shutdown_codec(&codec->dapm);
2839
		snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF);
L
Liam Girdwood 已提交
2840
	}
M
Mark Brown 已提交
2841 2842
}

2843
/* Module information */
2844
MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
2845 2846
MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
MODULE_LICENSE("GPL");