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