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