1 /* 2 * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management 3 * 4 * Copyright 2005 Wolfson Microelectronics PLC. 5 * Author: Liam Girdwood <lrg@slimlogic.co.uk> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or (at your 10 * option) any later version. 11 * 12 * Features: 13 * o Changes power status of internal codec blocks depending on the 14 * dynamic configuration of codec internal audio paths and active 15 * DAC's/ADC's. 16 * o Platform power domain - can support external components i.e. amps and 17 * mic/meadphone insertion events. 18 * o Automatic Mic Bias support 19 * o Jack insertion power event initiation - e.g. hp insertion will enable 20 * sinks, dacs, etc 21 * o Delayed powerdown of audio susbsystem to reduce pops between a quick 22 * device reopen. 23 * 24 * Todo: 25 * o DAPM power change sequencing - allow for configurable per 26 * codec sequences. 27 * o Support for analogue bias optimisation. 28 * o Support for reduced codec oversampling rates. 29 * o Support for reduced codec bias currents. 30 */ 31 32 #include <linux/module.h> 33 #include <linux/moduleparam.h> 34 #include <linux/init.h> 35 #include <linux/delay.h> 36 #include <linux/pm.h> 37 #include <linux/bitops.h> 38 #include <linux/platform_device.h> 39 #include <linux/jiffies.h> 40 #include <linux/debugfs.h> 41 #include <sound/core.h> 42 #include <sound/pcm.h> 43 #include <sound/pcm_params.h> 44 #include <sound/soc-dapm.h> 45 #include <sound/initval.h> 46 47 /* debug */ 48 #ifdef DEBUG 49 #define dump_dapm(codec, action) dbg_dump_dapm(codec, action) 50 #else 51 #define dump_dapm(codec, action) 52 #endif 53 54 /* dapm power sequences - make this per codec in the future */ 55 static int dapm_up_seq[] = { 56 snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic, 57 snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga, 58 snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post 59 }; 60 static int dapm_down_seq[] = { 61 snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, 62 snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic, 63 snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post 64 }; 65 66 static int dapm_status = 1; 67 module_param(dapm_status, int, 0); 68 MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries"); 69 70 static struct dentry *asoc_debugfs; 71 72 static u32 pop_time; 73 74 static void pop_wait(void) 75 { 76 if (pop_time) 77 schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time)); 78 } 79 80 static void pop_dbg(const char *fmt, ...) 81 { 82 va_list args; 83 84 va_start(args, fmt); 85 86 if (pop_time) { 87 vprintk(fmt, args); 88 pop_wait(); 89 } 90 91 va_end(args); 92 } 93 94 /* create a new dapm widget */ 95 static inline struct snd_soc_dapm_widget *dapm_cnew_widget( 96 const struct snd_soc_dapm_widget *_widget) 97 { 98 return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); 99 } 100 101 /* set up initial codec paths */ 102 static void dapm_set_path_status(struct snd_soc_dapm_widget *w, 103 struct snd_soc_dapm_path *p, int i) 104 { 105 switch (w->id) { 106 case snd_soc_dapm_switch: 107 case snd_soc_dapm_mixer: { 108 int val; 109 struct soc_mixer_control *mc = (struct soc_mixer_control *) 110 w->kcontrols[i].private_value; 111 unsigned int reg = mc->reg; 112 unsigned int shift = mc->shift; 113 int max = mc->max; 114 unsigned int mask = (1 << fls(max)) - 1; 115 unsigned int invert = mc->invert; 116 117 val = snd_soc_read(w->codec, reg); 118 val = (val >> shift) & mask; 119 120 if ((invert && !val) || (!invert && val)) 121 p->connect = 1; 122 else 123 p->connect = 0; 124 } 125 break; 126 case snd_soc_dapm_mux: { 127 struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value; 128 int val, item, bitmask; 129 130 for (bitmask = 1; bitmask < e->max; bitmask <<= 1) 131 ; 132 val = snd_soc_read(w->codec, e->reg); 133 item = (val >> e->shift_l) & (bitmask - 1); 134 135 p->connect = 0; 136 for (i = 0; i < e->max; i++) { 137 if (!(strcmp(p->name, e->texts[i])) && item == i) 138 p->connect = 1; 139 } 140 } 141 break; 142 /* does not effect routing - always connected */ 143 case snd_soc_dapm_pga: 144 case snd_soc_dapm_output: 145 case snd_soc_dapm_adc: 146 case snd_soc_dapm_input: 147 case snd_soc_dapm_dac: 148 case snd_soc_dapm_micbias: 149 case snd_soc_dapm_vmid: 150 p->connect = 1; 151 break; 152 /* does effect routing - dynamically connected */ 153 case snd_soc_dapm_hp: 154 case snd_soc_dapm_mic: 155 case snd_soc_dapm_spk: 156 case snd_soc_dapm_line: 157 case snd_soc_dapm_pre: 158 case snd_soc_dapm_post: 159 p->connect = 0; 160 break; 161 } 162 } 163 164 /* connect mux widget to it's interconnecting audio paths */ 165 static int dapm_connect_mux(struct snd_soc_codec *codec, 166 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, 167 struct snd_soc_dapm_path *path, const char *control_name, 168 const struct snd_kcontrol_new *kcontrol) 169 { 170 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 171 int i; 172 173 for (i = 0; i < e->max; i++) { 174 if (!(strcmp(control_name, e->texts[i]))) { 175 list_add(&path->list, &codec->dapm_paths); 176 list_add(&path->list_sink, &dest->sources); 177 list_add(&path->list_source, &src->sinks); 178 path->name = (char*)e->texts[i]; 179 dapm_set_path_status(dest, path, 0); 180 return 0; 181 } 182 } 183 184 return -ENODEV; 185 } 186 187 /* connect mixer widget to it's interconnecting audio paths */ 188 static int dapm_connect_mixer(struct snd_soc_codec *codec, 189 struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, 190 struct snd_soc_dapm_path *path, const char *control_name) 191 { 192 int i; 193 194 /* search for mixer kcontrol */ 195 for (i = 0; i < dest->num_kcontrols; i++) { 196 if (!strcmp(control_name, dest->kcontrols[i].name)) { 197 list_add(&path->list, &codec->dapm_paths); 198 list_add(&path->list_sink, &dest->sources); 199 list_add(&path->list_source, &src->sinks); 200 path->name = dest->kcontrols[i].name; 201 dapm_set_path_status(dest, path, i); 202 return 0; 203 } 204 } 205 return -ENODEV; 206 } 207 208 /* update dapm codec register bits */ 209 static int dapm_update_bits(struct snd_soc_dapm_widget *widget) 210 { 211 int change, power; 212 unsigned short old, new; 213 struct snd_soc_codec *codec = widget->codec; 214 215 /* check for valid widgets */ 216 if (widget->reg < 0 || widget->id == snd_soc_dapm_input || 217 widget->id == snd_soc_dapm_output || 218 widget->id == snd_soc_dapm_hp || 219 widget->id == snd_soc_dapm_mic || 220 widget->id == snd_soc_dapm_line || 221 widget->id == snd_soc_dapm_spk) 222 return 0; 223 224 power = widget->power; 225 if (widget->invert) 226 power = (power ? 0:1); 227 228 old = snd_soc_read(codec, widget->reg); 229 new = (old & ~(0x1 << widget->shift)) | (power << widget->shift); 230 231 change = old != new; 232 if (change) { 233 pop_dbg("pop test %s : %s in %d ms\n", widget->name, 234 widget->power ? "on" : "off", pop_time); 235 snd_soc_write(codec, widget->reg, new); 236 pop_wait(); 237 } 238 pr_debug("reg %x old %x new %x change %d\n", widget->reg, 239 old, new, change); 240 return change; 241 } 242 243 /* ramps the volume up or down to minimise pops before or after a 244 * DAPM power event */ 245 static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power) 246 { 247 const struct snd_kcontrol_new *k = widget->kcontrols; 248 249 if (widget->muted && !power) 250 return 0; 251 if (!widget->muted && power) 252 return 0; 253 254 if (widget->num_kcontrols && k) { 255 struct soc_mixer_control *mc = 256 (struct soc_mixer_control *)k->private_value; 257 unsigned int reg = mc->reg; 258 unsigned int shift = mc->shift; 259 int max = mc->max; 260 unsigned int mask = (1 << fls(max)) - 1; 261 unsigned int invert = mc->invert; 262 263 if (power) { 264 int i; 265 /* power up has happended, increase volume to last level */ 266 if (invert) { 267 for (i = max; i > widget->saved_value; i--) 268 snd_soc_update_bits(widget->codec, reg, mask, i); 269 } else { 270 for (i = 0; i < widget->saved_value; i++) 271 snd_soc_update_bits(widget->codec, reg, mask, i); 272 } 273 widget->muted = 0; 274 } else { 275 /* power down is about to occur, decrease volume to mute */ 276 int val = snd_soc_read(widget->codec, reg); 277 int i = widget->saved_value = (val >> shift) & mask; 278 if (invert) { 279 for (; i < mask; i++) 280 snd_soc_update_bits(widget->codec, reg, mask, i); 281 } else { 282 for (; i > 0; i--) 283 snd_soc_update_bits(widget->codec, reg, mask, i); 284 } 285 widget->muted = 1; 286 } 287 } 288 return 0; 289 } 290 291 /* create new dapm mixer control */ 292 static int dapm_new_mixer(struct snd_soc_codec *codec, 293 struct snd_soc_dapm_widget *w) 294 { 295 int i, ret = 0; 296 char name[32]; 297 struct snd_soc_dapm_path *path; 298 299 /* add kcontrol */ 300 for (i = 0; i < w->num_kcontrols; i++) { 301 302 /* match name */ 303 list_for_each_entry(path, &w->sources, list_sink) { 304 305 /* mixer/mux paths name must match control name */ 306 if (path->name != (char*)w->kcontrols[i].name) 307 continue; 308 309 /* add dapm control with long name */ 310 snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name); 311 path->long_name = kstrdup (name, GFP_KERNEL); 312 if (path->long_name == NULL) 313 return -ENOMEM; 314 315 path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, 316 path->long_name); 317 ret = snd_ctl_add(codec->card, path->kcontrol); 318 if (ret < 0) { 319 printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n", 320 path->long_name); 321 kfree(path->long_name); 322 path->long_name = NULL; 323 return ret; 324 } 325 } 326 } 327 return ret; 328 } 329 330 /* create new dapm mux control */ 331 static int dapm_new_mux(struct snd_soc_codec *codec, 332 struct snd_soc_dapm_widget *w) 333 { 334 struct snd_soc_dapm_path *path = NULL; 335 struct snd_kcontrol *kcontrol; 336 int ret = 0; 337 338 if (!w->num_kcontrols) { 339 printk(KERN_ERR "asoc: mux %s has no controls\n", w->name); 340 return -EINVAL; 341 } 342 343 kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); 344 ret = snd_ctl_add(codec->card, kcontrol); 345 if (ret < 0) 346 goto err; 347 348 list_for_each_entry(path, &w->sources, list_sink) 349 path->kcontrol = kcontrol; 350 351 return ret; 352 353 err: 354 printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name); 355 return ret; 356 } 357 358 /* create new dapm volume control */ 359 static int dapm_new_pga(struct snd_soc_codec *codec, 360 struct snd_soc_dapm_widget *w) 361 { 362 struct snd_kcontrol *kcontrol; 363 int ret = 0; 364 365 if (!w->num_kcontrols) 366 return -EINVAL; 367 368 kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); 369 ret = snd_ctl_add(codec->card, kcontrol); 370 if (ret < 0) { 371 printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name); 372 return ret; 373 } 374 375 return ret; 376 } 377 378 /* reset 'walked' bit for each dapm path */ 379 static inline void dapm_clear_walk(struct snd_soc_codec *codec) 380 { 381 struct snd_soc_dapm_path *p; 382 383 list_for_each_entry(p, &codec->dapm_paths, list) 384 p->walked = 0; 385 } 386 387 /* 388 * Recursively check for a completed path to an active or physically connected 389 * output widget. Returns number of complete paths. 390 */ 391 static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) 392 { 393 struct snd_soc_dapm_path *path; 394 int con = 0; 395 396 if (widget->id == snd_soc_dapm_adc && widget->active) 397 return 1; 398 399 if (widget->connected) { 400 /* connected pin ? */ 401 if (widget->id == snd_soc_dapm_output && !widget->ext) 402 return 1; 403 404 /* connected jack or spk ? */ 405 if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk || 406 widget->id == snd_soc_dapm_line) 407 return 1; 408 } 409 410 list_for_each_entry(path, &widget->sinks, list_source) { 411 if (path->walked) 412 continue; 413 414 if (path->sink && path->connect) { 415 path->walked = 1; 416 con += is_connected_output_ep(path->sink); 417 } 418 } 419 420 return con; 421 } 422 423 /* 424 * Recursively check for a completed path to an active or physically connected 425 * input widget. Returns number of complete paths. 426 */ 427 static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) 428 { 429 struct snd_soc_dapm_path *path; 430 int con = 0; 431 432 /* active stream ? */ 433 if (widget->id == snd_soc_dapm_dac && widget->active) 434 return 1; 435 436 if (widget->connected) { 437 /* connected pin ? */ 438 if (widget->id == snd_soc_dapm_input && !widget->ext) 439 return 1; 440 441 /* connected VMID/Bias for lower pops */ 442 if (widget->id == snd_soc_dapm_vmid) 443 return 1; 444 445 /* connected jack ? */ 446 if (widget->id == snd_soc_dapm_mic || widget->id == snd_soc_dapm_line) 447 return 1; 448 } 449 450 list_for_each_entry(path, &widget->sources, list_sink) { 451 if (path->walked) 452 continue; 453 454 if (path->source && path->connect) { 455 path->walked = 1; 456 con += is_connected_input_ep(path->source); 457 } 458 } 459 460 return con; 461 } 462 463 /* 464 * Handler for generic register modifier widget. 465 */ 466 int dapm_reg_event(struct snd_soc_dapm_widget *w, 467 struct snd_kcontrol *kcontrol, int event) 468 { 469 unsigned int val; 470 471 if (SND_SOC_DAPM_EVENT_ON(event)) 472 val = w->on_val; 473 else 474 val = w->off_val; 475 476 snd_soc_update_bits(w->codec, -(w->reg + 1), 477 w->mask << w->shift, val << w->shift); 478 479 return 0; 480 } 481 EXPORT_SYMBOL_GPL(dapm_reg_event); 482 483 /* 484 * Scan each dapm widget for complete audio path. 485 * A complete path is a route that has valid endpoints i.e.:- 486 * 487 * o DAC to output pin. 488 * o Input Pin to ADC. 489 * o Input pin to Output pin (bypass, sidetone) 490 * o DAC to ADC (loopback). 491 */ 492 static int dapm_power_widgets(struct snd_soc_codec *codec, int event) 493 { 494 struct snd_soc_dapm_widget *w; 495 int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power; 496 497 /* do we have a sequenced stream event */ 498 if (event == SND_SOC_DAPM_STREAM_START) { 499 c = ARRAY_SIZE(dapm_up_seq); 500 seq = dapm_up_seq; 501 } else if (event == SND_SOC_DAPM_STREAM_STOP) { 502 c = ARRAY_SIZE(dapm_down_seq); 503 seq = dapm_down_seq; 504 } 505 506 for(i = 0; i < c; i++) { 507 list_for_each_entry(w, &codec->dapm_widgets, list) { 508 509 /* is widget in stream order */ 510 if (seq && seq[i] && w->id != seq[i]) 511 continue; 512 513 /* vmid - no action */ 514 if (w->id == snd_soc_dapm_vmid) 515 continue; 516 517 /* active ADC */ 518 if (w->id == snd_soc_dapm_adc && w->active) { 519 in = is_connected_input_ep(w); 520 dapm_clear_walk(w->codec); 521 w->power = (in != 0) ? 1 : 0; 522 dapm_update_bits(w); 523 continue; 524 } 525 526 /* active DAC */ 527 if (w->id == snd_soc_dapm_dac && w->active) { 528 out = is_connected_output_ep(w); 529 dapm_clear_walk(w->codec); 530 w->power = (out != 0) ? 1 : 0; 531 dapm_update_bits(w); 532 continue; 533 } 534 535 /* pre and post event widgets */ 536 if (w->id == snd_soc_dapm_pre) { 537 if (!w->event) 538 continue; 539 540 if (event == SND_SOC_DAPM_STREAM_START) { 541 ret = w->event(w, 542 NULL, SND_SOC_DAPM_PRE_PMU); 543 if (ret < 0) 544 return ret; 545 } else if (event == SND_SOC_DAPM_STREAM_STOP) { 546 ret = w->event(w, 547 NULL, SND_SOC_DAPM_PRE_PMD); 548 if (ret < 0) 549 return ret; 550 } 551 continue; 552 } 553 if (w->id == snd_soc_dapm_post) { 554 if (!w->event) 555 continue; 556 557 if (event == SND_SOC_DAPM_STREAM_START) { 558 ret = w->event(w, 559 NULL, SND_SOC_DAPM_POST_PMU); 560 if (ret < 0) 561 return ret; 562 } else if (event == SND_SOC_DAPM_STREAM_STOP) { 563 ret = w->event(w, 564 NULL, SND_SOC_DAPM_POST_PMD); 565 if (ret < 0) 566 return ret; 567 } 568 continue; 569 } 570 571 /* all other widgets */ 572 in = is_connected_input_ep(w); 573 dapm_clear_walk(w->codec); 574 out = is_connected_output_ep(w); 575 dapm_clear_walk(w->codec); 576 power = (out != 0 && in != 0) ? 1 : 0; 577 power_change = (w->power == power) ? 0: 1; 578 w->power = power; 579 580 if (!power_change) 581 continue; 582 583 /* call any power change event handlers */ 584 if (w->event) 585 pr_debug("power %s event for %s flags %x\n", 586 w->power ? "on" : "off", 587 w->name, w->event_flags); 588 589 /* power up pre event */ 590 if (power && w->event && 591 (w->event_flags & SND_SOC_DAPM_PRE_PMU)) { 592 ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMU); 593 if (ret < 0) 594 return ret; 595 } 596 597 /* power down pre event */ 598 if (!power && w->event && 599 (w->event_flags & SND_SOC_DAPM_PRE_PMD)) { 600 ret = w->event(w, NULL, SND_SOC_DAPM_PRE_PMD); 601 if (ret < 0) 602 return ret; 603 } 604 605 /* Lower PGA volume to reduce pops */ 606 if (w->id == snd_soc_dapm_pga && !power) 607 dapm_set_pga(w, power); 608 609 dapm_update_bits(w); 610 611 /* Raise PGA volume to reduce pops */ 612 if (w->id == snd_soc_dapm_pga && power) 613 dapm_set_pga(w, power); 614 615 /* power up post event */ 616 if (power && w->event && 617 (w->event_flags & SND_SOC_DAPM_POST_PMU)) { 618 ret = w->event(w, 619 NULL, SND_SOC_DAPM_POST_PMU); 620 if (ret < 0) 621 return ret; 622 } 623 624 /* power down post event */ 625 if (!power && w->event && 626 (w->event_flags & SND_SOC_DAPM_POST_PMD)) { 627 ret = w->event(w, NULL, SND_SOC_DAPM_POST_PMD); 628 if (ret < 0) 629 return ret; 630 } 631 } 632 } 633 634 return ret; 635 } 636 637 #ifdef DEBUG 638 static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) 639 { 640 struct snd_soc_dapm_widget *w; 641 struct snd_soc_dapm_path *p = NULL; 642 int in, out; 643 644 printk("DAPM %s %s\n", codec->name, action); 645 646 list_for_each_entry(w, &codec->dapm_widgets, list) { 647 648 /* only display widgets that effect routing */ 649 switch (w->id) { 650 case snd_soc_dapm_pre: 651 case snd_soc_dapm_post: 652 case snd_soc_dapm_vmid: 653 continue; 654 case snd_soc_dapm_mux: 655 case snd_soc_dapm_output: 656 case snd_soc_dapm_input: 657 case snd_soc_dapm_switch: 658 case snd_soc_dapm_hp: 659 case snd_soc_dapm_mic: 660 case snd_soc_dapm_spk: 661 case snd_soc_dapm_line: 662 case snd_soc_dapm_micbias: 663 case snd_soc_dapm_dac: 664 case snd_soc_dapm_adc: 665 case snd_soc_dapm_pga: 666 case snd_soc_dapm_mixer: 667 if (w->name) { 668 in = is_connected_input_ep(w); 669 dapm_clear_walk(w->codec); 670 out = is_connected_output_ep(w); 671 dapm_clear_walk(w->codec); 672 printk("%s: %s in %d out %d\n", w->name, 673 w->power ? "On":"Off",in, out); 674 675 list_for_each_entry(p, &w->sources, list_sink) { 676 if (p->connect) 677 printk(" in %s %s\n", p->name ? p->name : "static", 678 p->source->name); 679 } 680 list_for_each_entry(p, &w->sinks, list_source) { 681 if (p->connect) 682 printk(" out %s %s\n", p->name ? p->name : "static", 683 p->sink->name); 684 } 685 } 686 break; 687 } 688 } 689 } 690 #endif 691 692 /* test and update the power status of a mux widget */ 693 static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, 694 struct snd_kcontrol *kcontrol, int mask, 695 int mux, int val, struct soc_enum *e) 696 { 697 struct snd_soc_dapm_path *path; 698 int found = 0; 699 700 if (widget->id != snd_soc_dapm_mux) 701 return -ENODEV; 702 703 if (!snd_soc_test_bits(widget->codec, e->reg, mask, val)) 704 return 0; 705 706 /* find dapm widget path assoc with kcontrol */ 707 list_for_each_entry(path, &widget->codec->dapm_paths, list) { 708 if (path->kcontrol != kcontrol) 709 continue; 710 711 if (!path->name || !e->texts[mux]) 712 continue; 713 714 found = 1; 715 /* we now need to match the string in the enum to the path */ 716 if (!(strcmp(path->name, e->texts[mux]))) 717 path->connect = 1; /* new connection */ 718 else 719 path->connect = 0; /* old connection must be powered down */ 720 } 721 722 if (found) { 723 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); 724 dump_dapm(widget->codec, "mux power update"); 725 } 726 727 return 0; 728 } 729 730 /* test and update the power status of a mixer or switch widget */ 731 static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, 732 struct snd_kcontrol *kcontrol, int reg, 733 int val_mask, int val, int invert) 734 { 735 struct snd_soc_dapm_path *path; 736 int found = 0; 737 738 if (widget->id != snd_soc_dapm_mixer && 739 widget->id != snd_soc_dapm_switch) 740 return -ENODEV; 741 742 if (!snd_soc_test_bits(widget->codec, reg, val_mask, val)) 743 return 0; 744 745 /* find dapm widget path assoc with kcontrol */ 746 list_for_each_entry(path, &widget->codec->dapm_paths, list) { 747 if (path->kcontrol != kcontrol) 748 continue; 749 750 /* found, now check type */ 751 found = 1; 752 if (val) 753 /* new connection */ 754 path->connect = invert ? 0:1; 755 else 756 /* old connection must be powered down */ 757 path->connect = invert ? 1:0; 758 break; 759 } 760 761 if (found) { 762 dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP); 763 dump_dapm(widget->codec, "mixer power update"); 764 } 765 766 return 0; 767 } 768 769 /* show dapm widget status in sys fs */ 770 static ssize_t dapm_widget_show(struct device *dev, 771 struct device_attribute *attr, char *buf) 772 { 773 struct snd_soc_device *devdata = dev_get_drvdata(dev); 774 struct snd_soc_codec *codec = devdata->codec; 775 struct snd_soc_dapm_widget *w; 776 int count = 0; 777 char *state = "not set"; 778 779 list_for_each_entry(w, &codec->dapm_widgets, list) { 780 781 /* only display widgets that burnm power */ 782 switch (w->id) { 783 case snd_soc_dapm_hp: 784 case snd_soc_dapm_mic: 785 case snd_soc_dapm_spk: 786 case snd_soc_dapm_line: 787 case snd_soc_dapm_micbias: 788 case snd_soc_dapm_dac: 789 case snd_soc_dapm_adc: 790 case snd_soc_dapm_pga: 791 case snd_soc_dapm_mixer: 792 if (w->name) 793 count += sprintf(buf + count, "%s: %s\n", 794 w->name, w->power ? "On":"Off"); 795 break; 796 default: 797 break; 798 } 799 } 800 801 switch (codec->bias_level) { 802 case SND_SOC_BIAS_ON: 803 state = "On"; 804 break; 805 case SND_SOC_BIAS_PREPARE: 806 state = "Prepare"; 807 break; 808 case SND_SOC_BIAS_STANDBY: 809 state = "Standby"; 810 break; 811 case SND_SOC_BIAS_OFF: 812 state = "Off"; 813 break; 814 } 815 count += sprintf(buf + count, "PM State: %s\n", state); 816 817 return count; 818 } 819 820 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL); 821 822 int snd_soc_dapm_sys_add(struct device *dev) 823 { 824 int ret = 0; 825 826 if (!dapm_status) 827 return 0; 828 829 ret = device_create_file(dev, &dev_attr_dapm_widget); 830 if (ret != 0) 831 return ret; 832 833 asoc_debugfs = debugfs_create_dir("asoc", NULL); 834 if (!IS_ERR(asoc_debugfs) && asoc_debugfs) 835 debugfs_create_u32("dapm_pop_time", 0744, asoc_debugfs, 836 &pop_time); 837 else 838 asoc_debugfs = NULL; 839 840 return 0; 841 } 842 843 static void snd_soc_dapm_sys_remove(struct device *dev) 844 { 845 if (dapm_status) { 846 device_remove_file(dev, &dev_attr_dapm_widget); 847 } 848 849 if (asoc_debugfs) 850 debugfs_remove_recursive(asoc_debugfs); 851 } 852 853 /* free all dapm widgets and resources */ 854 static void dapm_free_widgets(struct snd_soc_codec *codec) 855 { 856 struct snd_soc_dapm_widget *w, *next_w; 857 struct snd_soc_dapm_path *p, *next_p; 858 859 list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) { 860 list_del(&w->list); 861 kfree(w); 862 } 863 864 list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) { 865 list_del(&p->list); 866 kfree(p->long_name); 867 kfree(p); 868 } 869 } 870 871 static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec, 872 char *pin, int status) 873 { 874 struct snd_soc_dapm_widget *w; 875 876 list_for_each_entry(w, &codec->dapm_widgets, list) { 877 if (!strcmp(w->name, pin)) { 878 pr_debug("dapm: %s: pin %s\n", codec->name, pin); 879 w->connected = status; 880 return 0; 881 } 882 } 883 884 pr_err("dapm: %s: configuring unknown pin %s\n", codec->name, pin); 885 return -EINVAL; 886 } 887 888 /** 889 * snd_soc_dapm_sync - scan and power dapm paths 890 * @codec: audio codec 891 * 892 * Walks all dapm audio paths and powers widgets according to their 893 * stream or path usage. 894 * 895 * Returns 0 for success. 896 */ 897 int snd_soc_dapm_sync(struct snd_soc_codec *codec) 898 { 899 int ret = dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); 900 dump_dapm(codec, "sync"); 901 return ret; 902 } 903 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); 904 905 static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, 906 const char *sink, const char *control, const char *source) 907 { 908 struct snd_soc_dapm_path *path; 909 struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; 910 int ret = 0; 911 912 /* find src and dest widgets */ 913 list_for_each_entry(w, &codec->dapm_widgets, list) { 914 915 if (!wsink && !(strcmp(w->name, sink))) { 916 wsink = w; 917 continue; 918 } 919 if (!wsource && !(strcmp(w->name, source))) { 920 wsource = w; 921 } 922 } 923 924 if (wsource == NULL || wsink == NULL) 925 return -ENODEV; 926 927 path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); 928 if (!path) 929 return -ENOMEM; 930 931 path->source = wsource; 932 path->sink = wsink; 933 INIT_LIST_HEAD(&path->list); 934 INIT_LIST_HEAD(&path->list_source); 935 INIT_LIST_HEAD(&path->list_sink); 936 937 /* check for external widgets */ 938 if (wsink->id == snd_soc_dapm_input) { 939 if (wsource->id == snd_soc_dapm_micbias || 940 wsource->id == snd_soc_dapm_mic || 941 wsink->id == snd_soc_dapm_line || 942 wsink->id == snd_soc_dapm_output) 943 wsink->ext = 1; 944 } 945 if (wsource->id == snd_soc_dapm_output) { 946 if (wsink->id == snd_soc_dapm_spk || 947 wsink->id == snd_soc_dapm_hp || 948 wsink->id == snd_soc_dapm_line || 949 wsink->id == snd_soc_dapm_input) 950 wsource->ext = 1; 951 } 952 953 /* connect static paths */ 954 if (control == NULL) { 955 list_add(&path->list, &codec->dapm_paths); 956 list_add(&path->list_sink, &wsink->sources); 957 list_add(&path->list_source, &wsource->sinks); 958 path->connect = 1; 959 return 0; 960 } 961 962 /* connect dynamic paths */ 963 switch(wsink->id) { 964 case snd_soc_dapm_adc: 965 case snd_soc_dapm_dac: 966 case snd_soc_dapm_pga: 967 case snd_soc_dapm_input: 968 case snd_soc_dapm_output: 969 case snd_soc_dapm_micbias: 970 case snd_soc_dapm_vmid: 971 case snd_soc_dapm_pre: 972 case snd_soc_dapm_post: 973 list_add(&path->list, &codec->dapm_paths); 974 list_add(&path->list_sink, &wsink->sources); 975 list_add(&path->list_source, &wsource->sinks); 976 path->connect = 1; 977 return 0; 978 case snd_soc_dapm_mux: 979 ret = dapm_connect_mux(codec, wsource, wsink, path, control, 980 &wsink->kcontrols[0]); 981 if (ret != 0) 982 goto err; 983 break; 984 case snd_soc_dapm_switch: 985 case snd_soc_dapm_mixer: 986 ret = dapm_connect_mixer(codec, wsource, wsink, path, control); 987 if (ret != 0) 988 goto err; 989 break; 990 case snd_soc_dapm_hp: 991 case snd_soc_dapm_mic: 992 case snd_soc_dapm_line: 993 case snd_soc_dapm_spk: 994 list_add(&path->list, &codec->dapm_paths); 995 list_add(&path->list_sink, &wsink->sources); 996 list_add(&path->list_source, &wsource->sinks); 997 path->connect = 0; 998 return 0; 999 } 1000 return 0; 1001 1002 err: 1003 printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source, 1004 control, sink); 1005 kfree(path); 1006 return ret; 1007 } 1008 1009 /** 1010 * snd_soc_dapm_connect_input - connect dapm widgets 1011 * @codec: audio codec 1012 * @sink: name of target widget 1013 * @control: mixer control name 1014 * @source: name of source name 1015 * 1016 * Connects 2 dapm widgets together via a named audio path. The sink is 1017 * the widget receiving the audio signal, whilst the source is the sender 1018 * of the audio signal. 1019 * 1020 * This function has been deprecated in favour of snd_soc_dapm_add_routes(). 1021 * 1022 * Returns 0 for success else error. 1023 */ 1024 int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink, 1025 const char *control, const char *source) 1026 { 1027 return snd_soc_dapm_add_route(codec, sink, control, source); 1028 } 1029 EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input); 1030 1031 /** 1032 * snd_soc_dapm_add_routes - Add routes between DAPM widgets 1033 * @codec: codec 1034 * @route: audio routes 1035 * @num: number of routes 1036 * 1037 * Connects 2 dapm widgets together via a named audio path. The sink is 1038 * the widget receiving the audio signal, whilst the source is the sender 1039 * of the audio signal. 1040 * 1041 * Returns 0 for success else error. On error all resources can be freed 1042 * with a call to snd_soc_card_free(). 1043 */ 1044 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, 1045 const struct snd_soc_dapm_route *route, int num) 1046 { 1047 int i, ret; 1048 1049 for (i = 0; i < num; i++) { 1050 ret = snd_soc_dapm_add_route(codec, route->sink, 1051 route->control, route->source); 1052 if (ret < 0) { 1053 printk(KERN_ERR "Failed to add route %s->%s\n", 1054 route->source, 1055 route->sink); 1056 return ret; 1057 } 1058 route++; 1059 } 1060 1061 return 0; 1062 } 1063 EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); 1064 1065 /** 1066 * snd_soc_dapm_new_widgets - add new dapm widgets 1067 * @codec: audio codec 1068 * 1069 * Checks the codec for any new dapm widgets and creates them if found. 1070 * 1071 * Returns 0 for success. 1072 */ 1073 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) 1074 { 1075 struct snd_soc_dapm_widget *w; 1076 1077 list_for_each_entry(w, &codec->dapm_widgets, list) 1078 { 1079 if (w->new) 1080 continue; 1081 1082 switch(w->id) { 1083 case snd_soc_dapm_switch: 1084 case snd_soc_dapm_mixer: 1085 dapm_new_mixer(codec, w); 1086 break; 1087 case snd_soc_dapm_mux: 1088 dapm_new_mux(codec, w); 1089 break; 1090 case snd_soc_dapm_adc: 1091 case snd_soc_dapm_dac: 1092 case snd_soc_dapm_pga: 1093 dapm_new_pga(codec, w); 1094 break; 1095 case snd_soc_dapm_input: 1096 case snd_soc_dapm_output: 1097 case snd_soc_dapm_micbias: 1098 case snd_soc_dapm_spk: 1099 case snd_soc_dapm_hp: 1100 case snd_soc_dapm_mic: 1101 case snd_soc_dapm_line: 1102 case snd_soc_dapm_vmid: 1103 case snd_soc_dapm_pre: 1104 case snd_soc_dapm_post: 1105 break; 1106 } 1107 w->new = 1; 1108 } 1109 1110 dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP); 1111 return 0; 1112 } 1113 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets); 1114 1115 /** 1116 * snd_soc_dapm_get_volsw - dapm mixer get callback 1117 * @kcontrol: mixer control 1118 * @uinfo: control element information 1119 * 1120 * Callback to get the value of a dapm mixer control. 1121 * 1122 * Returns 0 for success. 1123 */ 1124 int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, 1125 struct snd_ctl_elem_value *ucontrol) 1126 { 1127 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); 1128 struct soc_mixer_control *mc = 1129 (struct soc_mixer_control *)kcontrol->private_value; 1130 unsigned int reg = mc->reg; 1131 unsigned int shift = mc->shift; 1132 unsigned int rshift = mc->rshift; 1133 int max = mc->max; 1134 unsigned int invert = mc->invert; 1135 unsigned int mask = (1 << fls(max)) - 1; 1136 1137 /* return the saved value if we are powered down */ 1138 if (widget->id == snd_soc_dapm_pga && !widget->power) { 1139 ucontrol->value.integer.value[0] = widget->saved_value; 1140 return 0; 1141 } 1142 1143 ucontrol->value.integer.value[0] = 1144 (snd_soc_read(widget->codec, reg) >> shift) & mask; 1145 if (shift != rshift) 1146 ucontrol->value.integer.value[1] = 1147 (snd_soc_read(widget->codec, reg) >> rshift) & mask; 1148 if (invert) { 1149 ucontrol->value.integer.value[0] = 1150 max - ucontrol->value.integer.value[0]; 1151 if (shift != rshift) 1152 ucontrol->value.integer.value[1] = 1153 max - ucontrol->value.integer.value[1]; 1154 } 1155 1156 return 0; 1157 } 1158 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); 1159 1160 /** 1161 * snd_soc_dapm_put_volsw - dapm mixer set callback 1162 * @kcontrol: mixer control 1163 * @uinfo: control element information 1164 * 1165 * Callback to set the value of a dapm mixer control. 1166 * 1167 * Returns 0 for success. 1168 */ 1169 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, 1170 struct snd_ctl_elem_value *ucontrol) 1171 { 1172 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); 1173 struct soc_mixer_control *mc = 1174 (struct soc_mixer_control *)kcontrol->private_value; 1175 unsigned int reg = mc->reg; 1176 unsigned int shift = mc->shift; 1177 unsigned int rshift = mc->rshift; 1178 int max = mc->max; 1179 unsigned int mask = (1 << fls(max)) - 1; 1180 unsigned int invert = mc->invert; 1181 unsigned short val, val2, val_mask; 1182 int ret; 1183 1184 val = (ucontrol->value.integer.value[0] & mask); 1185 1186 if (invert) 1187 val = max - val; 1188 val_mask = mask << shift; 1189 val = val << shift; 1190 if (shift != rshift) { 1191 val2 = (ucontrol->value.integer.value[1] & mask); 1192 if (invert) 1193 val2 = max - val2; 1194 val_mask |= mask << rshift; 1195 val |= val2 << rshift; 1196 } 1197 1198 mutex_lock(&widget->codec->mutex); 1199 widget->value = val; 1200 1201 /* save volume value if the widget is powered down */ 1202 if (widget->id == snd_soc_dapm_pga && !widget->power) { 1203 widget->saved_value = val; 1204 mutex_unlock(&widget->codec->mutex); 1205 return 1; 1206 } 1207 1208 dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert); 1209 if (widget->event) { 1210 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { 1211 ret = widget->event(widget, kcontrol, 1212 SND_SOC_DAPM_PRE_REG); 1213 if (ret < 0) { 1214 ret = 1; 1215 goto out; 1216 } 1217 } 1218 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); 1219 if (widget->event_flags & SND_SOC_DAPM_POST_REG) 1220 ret = widget->event(widget, kcontrol, 1221 SND_SOC_DAPM_POST_REG); 1222 } else 1223 ret = snd_soc_update_bits(widget->codec, reg, val_mask, val); 1224 1225 out: 1226 mutex_unlock(&widget->codec->mutex); 1227 return ret; 1228 } 1229 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw); 1230 1231 /** 1232 * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback 1233 * @kcontrol: mixer control 1234 * @uinfo: control element information 1235 * 1236 * Callback to get the value of a dapm enumerated double mixer control. 1237 * 1238 * Returns 0 for success. 1239 */ 1240 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, 1241 struct snd_ctl_elem_value *ucontrol) 1242 { 1243 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); 1244 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 1245 unsigned short val, bitmask; 1246 1247 for (bitmask = 1; bitmask < e->max; bitmask <<= 1) 1248 ; 1249 val = snd_soc_read(widget->codec, e->reg); 1250 ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1); 1251 if (e->shift_l != e->shift_r) 1252 ucontrol->value.enumerated.item[1] = 1253 (val >> e->shift_r) & (bitmask - 1); 1254 1255 return 0; 1256 } 1257 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); 1258 1259 /** 1260 * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback 1261 * @kcontrol: mixer control 1262 * @uinfo: control element information 1263 * 1264 * Callback to set the value of a dapm enumerated double mixer control. 1265 * 1266 * Returns 0 for success. 1267 */ 1268 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, 1269 struct snd_ctl_elem_value *ucontrol) 1270 { 1271 struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol); 1272 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 1273 unsigned short val, mux; 1274 unsigned short mask, bitmask; 1275 int ret = 0; 1276 1277 for (bitmask = 1; bitmask < e->max; bitmask <<= 1) 1278 ; 1279 if (ucontrol->value.enumerated.item[0] > e->max - 1) 1280 return -EINVAL; 1281 mux = ucontrol->value.enumerated.item[0]; 1282 val = mux << e->shift_l; 1283 mask = (bitmask - 1) << e->shift_l; 1284 if (e->shift_l != e->shift_r) { 1285 if (ucontrol->value.enumerated.item[1] > e->max - 1) 1286 return -EINVAL; 1287 val |= ucontrol->value.enumerated.item[1] << e->shift_r; 1288 mask |= (bitmask - 1) << e->shift_r; 1289 } 1290 1291 mutex_lock(&widget->codec->mutex); 1292 widget->value = val; 1293 dapm_mux_update_power(widget, kcontrol, mask, mux, val, e); 1294 if (widget->event) { 1295 if (widget->event_flags & SND_SOC_DAPM_PRE_REG) { 1296 ret = widget->event(widget, 1297 kcontrol, SND_SOC_DAPM_PRE_REG); 1298 if (ret < 0) 1299 goto out; 1300 } 1301 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); 1302 if (widget->event_flags & SND_SOC_DAPM_POST_REG) 1303 ret = widget->event(widget, 1304 kcontrol, SND_SOC_DAPM_POST_REG); 1305 } else 1306 ret = snd_soc_update_bits(widget->codec, e->reg, mask, val); 1307 1308 out: 1309 mutex_unlock(&widget->codec->mutex); 1310 return ret; 1311 } 1312 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); 1313 1314 /** 1315 * snd_soc_dapm_new_control - create new dapm control 1316 * @codec: audio codec 1317 * @widget: widget template 1318 * 1319 * Creates a new dapm control based upon the template. 1320 * 1321 * Returns 0 for success else error. 1322 */ 1323 int snd_soc_dapm_new_control(struct snd_soc_codec *codec, 1324 const struct snd_soc_dapm_widget *widget) 1325 { 1326 struct snd_soc_dapm_widget *w; 1327 1328 if ((w = dapm_cnew_widget(widget)) == NULL) 1329 return -ENOMEM; 1330 1331 w->codec = codec; 1332 INIT_LIST_HEAD(&w->sources); 1333 INIT_LIST_HEAD(&w->sinks); 1334 INIT_LIST_HEAD(&w->list); 1335 list_add(&w->list, &codec->dapm_widgets); 1336 1337 /* machine layer set ups unconnected pins and insertions */ 1338 w->connected = 1; 1339 return 0; 1340 } 1341 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); 1342 1343 /** 1344 * snd_soc_dapm_new_controls - create new dapm controls 1345 * @codec: audio codec 1346 * @widget: widget array 1347 * @num: number of widgets 1348 * 1349 * Creates new DAPM controls based upon the templates. 1350 * 1351 * Returns 0 for success else error. 1352 */ 1353 int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, 1354 const struct snd_soc_dapm_widget *widget, 1355 int num) 1356 { 1357 int i, ret; 1358 1359 for (i = 0; i < num; i++) { 1360 ret = snd_soc_dapm_new_control(codec, widget); 1361 if (ret < 0) 1362 return ret; 1363 widget++; 1364 } 1365 return 0; 1366 } 1367 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); 1368 1369 1370 /** 1371 * snd_soc_dapm_stream_event - send a stream event to the dapm core 1372 * @codec: audio codec 1373 * @stream: stream name 1374 * @event: stream event 1375 * 1376 * Sends a stream event to the dapm core. The core then makes any 1377 * necessary widget power changes. 1378 * 1379 * Returns 0 for success else error. 1380 */ 1381 int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, 1382 char *stream, int event) 1383 { 1384 struct snd_soc_dapm_widget *w; 1385 1386 if (stream == NULL) 1387 return 0; 1388 1389 mutex_lock(&codec->mutex); 1390 list_for_each_entry(w, &codec->dapm_widgets, list) 1391 { 1392 if (!w->sname) 1393 continue; 1394 pr_debug("widget %s\n %s stream %s event %d\n", 1395 w->name, w->sname, stream, event); 1396 if (strstr(w->sname, stream)) { 1397 switch(event) { 1398 case SND_SOC_DAPM_STREAM_START: 1399 w->active = 1; 1400 break; 1401 case SND_SOC_DAPM_STREAM_STOP: 1402 w->active = 0; 1403 break; 1404 case SND_SOC_DAPM_STREAM_SUSPEND: 1405 if (w->active) 1406 w->suspend = 1; 1407 w->active = 0; 1408 break; 1409 case SND_SOC_DAPM_STREAM_RESUME: 1410 if (w->suspend) { 1411 w->active = 1; 1412 w->suspend = 0; 1413 } 1414 break; 1415 case SND_SOC_DAPM_STREAM_PAUSE_PUSH: 1416 break; 1417 case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: 1418 break; 1419 } 1420 } 1421 } 1422 mutex_unlock(&codec->mutex); 1423 1424 dapm_power_widgets(codec, event); 1425 dump_dapm(codec, __func__); 1426 return 0; 1427 } 1428 EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); 1429 1430 /** 1431 * snd_soc_dapm_set_bias_level - set the bias level for the system 1432 * @socdev: audio device 1433 * @level: level to configure 1434 * 1435 * Configure the bias (power) levels for the SoC audio device. 1436 * 1437 * Returns 0 for success else error. 1438 */ 1439 int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, 1440 enum snd_soc_bias_level level) 1441 { 1442 struct snd_soc_codec *codec = socdev->codec; 1443 struct snd_soc_machine *machine = socdev->machine; 1444 int ret = 0; 1445 1446 if (machine->set_bias_level) 1447 ret = machine->set_bias_level(machine, level); 1448 if (ret == 0 && codec->set_bias_level) 1449 ret = codec->set_bias_level(codec, level); 1450 1451 return ret; 1452 } 1453 1454 /** 1455 * snd_soc_dapm_enable_pin - enable pin. 1456 * @snd_soc_codec: SoC codec 1457 * @pin: pin name 1458 * 1459 * Enables input/output pin and it's parents or children widgets iff there is 1460 * a valid audio route and active audio stream. 1461 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to 1462 * do any widget power switching. 1463 */ 1464 int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin) 1465 { 1466 return snd_soc_dapm_set_pin(codec, pin, 1); 1467 } 1468 EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); 1469 1470 /** 1471 * snd_soc_dapm_disable_pin - disable pin. 1472 * @codec: SoC codec 1473 * @pin: pin name 1474 * 1475 * Disables input/output pin and it's parents or children widgets. 1476 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to 1477 * do any widget power switching. 1478 */ 1479 int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin) 1480 { 1481 return snd_soc_dapm_set_pin(codec, pin, 0); 1482 } 1483 EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); 1484 1485 /** 1486 * snd_soc_dapm_nc_pin - permanently disable pin. 1487 * @codec: SoC codec 1488 * @pin: pin name 1489 * 1490 * Marks the specified pin as being not connected, disabling it along 1491 * any parent or child widgets. At present this is identical to 1492 * snd_soc_dapm_disable_pin() but in future it will be extended to do 1493 * additional things such as disabling controls which only affect 1494 * paths through the pin. 1495 * 1496 * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to 1497 * do any widget power switching. 1498 */ 1499 int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, char *pin) 1500 { 1501 return snd_soc_dapm_set_pin(codec, pin, 0); 1502 } 1503 EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); 1504 1505 /** 1506 * snd_soc_dapm_get_pin_status - get audio pin status 1507 * @codec: audio codec 1508 * @pin: audio signal pin endpoint (or start point) 1509 * 1510 * Get audio pin status - connected or disconnected. 1511 * 1512 * Returns 1 for connected otherwise 0. 1513 */ 1514 int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin) 1515 { 1516 struct snd_soc_dapm_widget *w; 1517 1518 list_for_each_entry(w, &codec->dapm_widgets, list) { 1519 if (!strcmp(w->name, pin)) 1520 return w->connected; 1521 } 1522 1523 return 0; 1524 } 1525 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status); 1526 1527 /** 1528 * snd_soc_dapm_free - free dapm resources 1529 * @socdev: SoC device 1530 * 1531 * Free all dapm widgets and resources. 1532 */ 1533 void snd_soc_dapm_free(struct snd_soc_device *socdev) 1534 { 1535 struct snd_soc_codec *codec = socdev->codec; 1536 1537 snd_soc_dapm_sys_remove(socdev->dev); 1538 dapm_free_widgets(codec); 1539 } 1540 EXPORT_SYMBOL_GPL(snd_soc_dapm_free); 1541 1542 /* Module information */ 1543 MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); 1544 MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC"); 1545 MODULE_LICENSE("GPL"); 1546