linux/sound/soc/codecs/wm8958-dsp2.c
<<
>>
Prefs
   1/*
   2 * wm8958-dsp2.c  --  WM8958 DSP2 support
   3 *
   4 * Copyright 2011 Wolfson Microelectronics plc
   5 *
   6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/moduleparam.h>
  15#include <linux/init.h>
  16#include <linux/delay.h>
  17#include <linux/pm.h>
  18#include <linux/i2c.h>
  19#include <linux/platform_device.h>
  20#include <linux/slab.h>
  21#include <sound/soc.h>
  22#include <sound/initval.h>
  23#include <sound/tlv.h>
  24#include <trace/events/asoc.h>
  25
  26#include <linux/mfd/wm8994/core.h>
  27#include <linux/mfd/wm8994/registers.h>
  28#include <linux/mfd/wm8994/pdata.h>
  29#include <linux/mfd/wm8994/gpio.h>
  30
  31#include "wm8994.h"
  32
  33#define WM_FW_BLOCK_INFO 0xff
  34#define WM_FW_BLOCK_PM   0x00
  35#define WM_FW_BLOCK_X    0x01
  36#define WM_FW_BLOCK_Y    0x02
  37#define WM_FW_BLOCK_Z    0x03
  38#define WM_FW_BLOCK_I    0x06
  39#define WM_FW_BLOCK_A    0x08
  40#define WM_FW_BLOCK_C    0x0c
  41
  42static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
  43                          const struct firmware *fw, bool check)
  44{
  45        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
  46        u64 data64;
  47        u32 data32;
  48        const u8 *data;
  49        char *str;
  50        size_t block_len, len;
  51        int ret = 0;
  52
  53        /* Suppress unneeded downloads */
  54        if (wm8994->cur_fw == fw)
  55                return 0;
  56
  57        if (fw->size < 32) {
  58                dev_err(codec->dev, "%s: firmware too short\n", name);
  59                goto err;
  60        }
  61
  62        if (memcmp(fw->data, "WMFW", 4) != 0) {
  63                memcpy(&data32, fw->data, sizeof(data32));
  64                data32 = be32_to_cpu(data32);
  65                dev_err(codec->dev, "%s: firmware has bad file magic %08x\n",
  66                        name, data32);
  67                goto err;
  68        }
  69
  70        memcpy(&data32, fw->data + 4, sizeof(data32));
  71        len = be32_to_cpu(data32);
  72
  73        memcpy(&data32, fw->data + 8, sizeof(data32));
  74        data32 = be32_to_cpu(data32);
  75        if ((data32 >> 24) & 0xff) {
  76                dev_err(codec->dev, "%s: unsupported firmware version %d\n",
  77                        name, (data32 >> 24) & 0xff);
  78                goto err;
  79        }
  80        if ((data32 & 0xffff) != 8958) {
  81                dev_err(codec->dev, "%s: unsupported target device %d\n",
  82                        name, data32 & 0xffff);
  83                goto err;
  84        }
  85        if (((data32 >> 16) & 0xff) != 0xc) {
  86                dev_err(codec->dev, "%s: unsupported target core %d\n",
  87                        name, (data32 >> 16) & 0xff);
  88                goto err;
  89        }
  90
  91        if (check) {
  92                memcpy(&data64, fw->data + 24, sizeof(u64));
  93                dev_info(codec->dev, "%s timestamp %llx\n",
  94                         name, be64_to_cpu(data64));
  95        } else {
  96                snd_soc_write(codec, 0x102, 0x2);
  97                snd_soc_write(codec, 0x900, 0x2);
  98        }
  99
 100        data = fw->data + len;
 101        len = fw->size - len;
 102        while (len) {
 103                if (len < 12) {
 104                        dev_err(codec->dev, "%s short data block of %zd\n",
 105                                name, len);
 106                        goto err;
 107                }
 108
 109                memcpy(&data32, data + 4, sizeof(data32));
 110                block_len = be32_to_cpu(data32);
 111                if (block_len + 8 > len) {
 112                        dev_err(codec->dev, "%zd byte block longer than file\n",
 113                                block_len);
 114                        goto err;
 115                }
 116                if (block_len == 0) {
 117                        dev_err(codec->dev, "Zero length block\n");
 118                        goto err;
 119                }
 120
 121                memcpy(&data32, data, sizeof(data32));
 122                data32 = be32_to_cpu(data32);
 123
 124                switch ((data32 >> 24) & 0xff) {
 125                case WM_FW_BLOCK_INFO:
 126                        /* Informational text */
 127                        if (!check)
 128                                break;
 129
 130                        str = kzalloc(block_len + 1, GFP_KERNEL);
 131                        if (str) {
 132                                memcpy(str, data + 8, block_len);
 133                                dev_info(codec->dev, "%s: %s\n", name, str);
 134                                kfree(str);
 135                        } else {
 136                                dev_err(codec->dev, "Out of memory\n");
 137                        }
 138                        break;
 139                case WM_FW_BLOCK_PM:
 140                case WM_FW_BLOCK_X:
 141                case WM_FW_BLOCK_Y:
 142                case WM_FW_BLOCK_Z:
 143                case WM_FW_BLOCK_I:
 144                case WM_FW_BLOCK_A:
 145                case WM_FW_BLOCK_C:
 146                        dev_dbg(codec->dev, "%s: %zd bytes of %x@%x\n", name,
 147                                block_len, (data32 >> 24) & 0xff,
 148                                data32 & 0xffffff);
 149
 150                        if (check)
 151                                break;
 152
 153                        data32 &= 0xffffff;
 154
 155                        wm8994_bulk_write(codec->control_data,
 156                                          data32 & 0xffffff,
 157                                          block_len / 2,
 158                                          (void *)(data + 8));
 159
 160                        break;
 161                default:
 162                        dev_warn(codec->dev, "%s: unknown block type %d\n",
 163                                 name, (data32 >> 24) & 0xff);
 164                        break;
 165                }
 166
 167                /* Round up to the next 32 bit word */
 168                block_len += block_len % 4;
 169
 170                data += block_len + 8;
 171                len -= block_len + 8;
 172        }
 173
 174        if (!check) {
 175                dev_dbg(codec->dev, "%s: download done\n", name);
 176                wm8994->cur_fw = fw;
 177        } else {
 178                dev_info(codec->dev, "%s: got firmware\n", name);
 179        }
 180
 181        goto ok;
 182
 183err:
 184        ret = -EINVAL;
 185ok:
 186        if (!check) {
 187                snd_soc_write(codec, 0x900, 0x0);
 188                snd_soc_write(codec, 0x102, 0x0);
 189        }
 190
 191        return ret;
 192}
 193
 194static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
 195{
 196        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 197        struct wm8994_pdata *pdata = wm8994->pdata;
 198        int i;
 199
 200        /* If the DSP is already running then noop */
 201        if (snd_soc_read(codec, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
 202                return;
 203
 204        /* If we have MBC firmware download it */
 205        if (wm8994->mbc)
 206                wm8958_dsp2_fw(codec, "MBC", wm8994->mbc, false);
 207
 208        snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
 209                            WM8958_DSP2_ENA, WM8958_DSP2_ENA);
 210
 211        /* If we've got user supplied MBC settings use them */
 212        if (pdata && pdata->num_mbc_cfgs) {
 213                struct wm8958_mbc_cfg *cfg
 214                        = &pdata->mbc_cfgs[wm8994->mbc_cfg];
 215
 216                for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
 217                        snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
 218                                      cfg->coeff_regs[i]);
 219
 220                for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
 221                        snd_soc_write(codec,
 222                                      i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
 223                                      cfg->cutoff_regs[i]);
 224        }
 225
 226        /* Run the DSP */
 227        snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
 228                      WM8958_DSP2_RUNR);
 229
 230        /* And we're off! */
 231        snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
 232                            WM8958_MBC_ENA |
 233                            WM8958_MBC_SEL_MASK,
 234                            path << WM8958_MBC_SEL_SHIFT |
 235                            WM8958_MBC_ENA);
 236}
 237
 238static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
 239{
 240        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 241        struct wm8994_pdata *pdata = wm8994->pdata;
 242        int i, ena;
 243
 244        if (wm8994->mbc_vss)
 245                wm8958_dsp2_fw(codec, "MBC+VSS", wm8994->mbc_vss, false);
 246
 247        snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
 248                            WM8958_DSP2_ENA, WM8958_DSP2_ENA);
 249
 250        /* If we've got user supplied settings use them */
 251        if (pdata && pdata->num_mbc_cfgs) {
 252                struct wm8958_mbc_cfg *cfg
 253                        = &pdata->mbc_cfgs[wm8994->mbc_cfg];
 254
 255                for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
 256                        snd_soc_write(codec, i + 0x2800,
 257                                      cfg->combined_regs[i]);
 258        }
 259
 260        if (pdata && pdata->num_vss_cfgs) {
 261                struct wm8958_vss_cfg *cfg
 262                        = &pdata->vss_cfgs[wm8994->vss_cfg];
 263
 264                for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
 265                        snd_soc_write(codec, i + 0x2600, cfg->regs[i]);
 266        }
 267
 268        if (pdata && pdata->num_vss_hpf_cfgs) {
 269                struct wm8958_vss_hpf_cfg *cfg
 270                        = &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg];
 271
 272                for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
 273                        snd_soc_write(codec, i + 0x2400, cfg->regs[i]);
 274        }
 275
 276        /* Run the DSP */
 277        snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
 278                      WM8958_DSP2_RUNR);
 279
 280        /* Enable the algorithms we've selected */
 281        ena = 0;
 282        if (wm8994->mbc_ena[path])
 283                ena |= 0x8;
 284        if (wm8994->hpf2_ena[path])
 285                ena |= 0x4;
 286        if (wm8994->hpf1_ena[path])
 287                ena |= 0x2;
 288        if (wm8994->vss_ena[path])
 289                ena |= 0x1;
 290
 291        snd_soc_write(codec, 0x2201, ena);
 292
 293        /* Switch the DSP into the data path */
 294        snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
 295                            WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
 296                            path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
 297}
 298
 299static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
 300{
 301        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 302        struct wm8994_pdata *pdata = wm8994->pdata;
 303        int i;
 304
 305        wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false);
 306
 307        snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
 308                            WM8958_DSP2_ENA, WM8958_DSP2_ENA);
 309
 310        /* If we've got user supplied settings use them */
 311        if (pdata && pdata->num_enh_eq_cfgs) {
 312                struct wm8958_enh_eq_cfg *cfg
 313                        = &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg];
 314
 315                for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
 316                        snd_soc_write(codec, i + 0x2200,
 317                                      cfg->regs[i]);
 318        }
 319
 320        /* Run the DSP */
 321        snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
 322                      WM8958_DSP2_RUNR);
 323
 324        /* Switch the DSP into the data path */
 325        snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
 326                            WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
 327                            path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
 328}
 329
 330static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
 331{
 332        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 333        int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
 334        int ena, reg, aif;
 335
 336        switch (path) {
 337        case 0:
 338                pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
 339                aif = 0;
 340                break;
 341        case 1:
 342                pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
 343                aif = 0;
 344                break;
 345        case 2:
 346                pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
 347                aif = 1;
 348                break;
 349        default:
 350                BUG();
 351                return;
 352        }
 353
 354        /* Do we have both an active AIF and an active algorithm? */
 355        ena = wm8994->mbc_ena[path] || wm8994->vss_ena[path] ||
 356                wm8994->hpf1_ena[path] || wm8994->hpf2_ena[path] ||
 357                wm8994->enh_eq_ena[path];
 358        if (!pwr_reg)
 359                ena = 0;
 360
 361        reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
 362
 363        dev_dbg(codec->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
 364                path, wm8994->dsp_active, start, pwr_reg, reg);
 365
 366        if (start && ena) {
 367                /* If the DSP is already running then noop */
 368                if (reg & WM8958_DSP2_ENA)
 369                        return;
 370
 371                /* If either AIFnCLK is not yet enabled postpone */
 372                if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
 373                      & WM8994_AIF1CLK_ENA_MASK) &&
 374                    !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
 375                      & WM8994_AIF2CLK_ENA_MASK))
 376                        return;
 377
 378                /* Switch the clock over to the appropriate AIF */
 379                snd_soc_update_bits(codec, WM8994_CLOCKING_1,
 380                                    WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
 381                                    aif << WM8958_DSP2CLK_SRC_SHIFT |
 382                                    WM8958_DSP2CLK_ENA);
 383
 384                if (wm8994->enh_eq_ena[path])
 385                        wm8958_dsp_start_enh_eq(codec, path);
 386                else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] ||
 387                    wm8994->hpf2_ena[path])
 388                        wm8958_dsp_start_vss(codec, path);
 389                else if (wm8994->mbc_ena[path])
 390                        wm8958_dsp_start_mbc(codec, path);
 391
 392                wm8994->dsp_active = path;
 393
 394                dev_dbg(codec->dev, "DSP running in path %d\n", path);
 395        }
 396
 397        if (!start && wm8994->dsp_active == path) {
 398                /* If the DSP is already stopped then noop */
 399                if (!(reg & WM8958_DSP2_ENA))
 400                        return;
 401
 402                snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
 403                                    WM8958_MBC_ENA, 0); 
 404                snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
 405                              WM8958_DSP2_STOP);
 406                snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
 407                                    WM8958_DSP2_ENA, 0);
 408                snd_soc_update_bits(codec, WM8994_CLOCKING_1,
 409                                    WM8958_DSP2CLK_ENA, 0);
 410
 411                wm8994->dsp_active = -1;
 412
 413                dev_dbg(codec->dev, "DSP stopped\n");
 414        }
 415}
 416
 417int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
 418                  struct snd_kcontrol *kcontrol, int event)
 419{
 420        struct snd_soc_codec *codec = w->codec;
 421        int i;
 422
 423        switch (event) {
 424        case SND_SOC_DAPM_POST_PMU:
 425        case SND_SOC_DAPM_PRE_PMU:
 426                for (i = 0; i < 3; i++)
 427                        wm8958_dsp_apply(codec, i, 1);
 428                break;
 429        case SND_SOC_DAPM_POST_PMD:
 430        case SND_SOC_DAPM_PRE_PMD:
 431                for (i = 0; i < 3; i++)
 432                        wm8958_dsp_apply(codec, i, 0);
 433                break;
 434        }
 435
 436        return 0;
 437}
 438
 439/* Check if DSP2 is in use on another AIF */
 440static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
 441{
 442        int i;
 443
 444        for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
 445                if (i == aif)
 446                        continue;
 447                if (wm8994->mbc_ena[i] || wm8994->vss_ena[i] ||
 448                    wm8994->hpf1_ena[i] || wm8994->hpf2_ena[i])
 449                        return 1;
 450        }
 451
 452        return 0;
 453}
 454
 455static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
 456                               struct snd_ctl_elem_value *ucontrol)
 457{
 458        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 459        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 460        struct wm8994_pdata *pdata = wm8994->pdata;
 461        int value = ucontrol->value.integer.value[0];
 462        int reg;
 463
 464        /* Don't allow on the fly reconfiguration */
 465        reg = snd_soc_read(codec, WM8994_CLOCKING_1);
 466        if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 467                return -EBUSY;
 468
 469        if (value >= pdata->num_mbc_cfgs)
 470                return -EINVAL;
 471
 472        wm8994->mbc_cfg = value;
 473
 474        return 0;
 475}
 476
 477static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
 478                               struct snd_ctl_elem_value *ucontrol)
 479{
 480        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 481        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 482
 483        ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
 484
 485        return 0;
 486}
 487
 488static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
 489                           struct snd_ctl_elem_info *uinfo)
 490{
 491        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 492        uinfo->count = 1;
 493        uinfo->value.integer.min = 0;
 494        uinfo->value.integer.max = 1;
 495        return 0;
 496}
 497
 498static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
 499                          struct snd_ctl_elem_value *ucontrol)
 500{
 501        int mbc = kcontrol->private_value;
 502        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 503        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 504
 505        ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
 506
 507        return 0;
 508}
 509
 510static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
 511                          struct snd_ctl_elem_value *ucontrol)
 512{
 513        int mbc = kcontrol->private_value;
 514        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 515        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 516
 517        if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
 518                return 0;
 519
 520        if (ucontrol->value.integer.value[0] > 1)
 521                return -EINVAL;
 522
 523        if (wm8958_dsp2_busy(wm8994, mbc)) {
 524                dev_dbg(codec->dev, "DSP2 active on %d already\n", mbc);
 525                return -EBUSY;
 526        }
 527
 528        if (wm8994->enh_eq_ena[mbc])
 529                return -EBUSY;
 530
 531        wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
 532
 533        wm8958_dsp_apply(codec, mbc, wm8994->mbc_ena[mbc]);
 534
 535        return 0;
 536}
 537
 538#define WM8958_MBC_SWITCH(xname, xval) {\
 539        .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 540        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 541        .info = wm8958_mbc_info, \
 542        .get = wm8958_mbc_get, .put = wm8958_mbc_put, \
 543        .private_value = xval }
 544
 545static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
 546                               struct snd_ctl_elem_value *ucontrol)
 547{
 548        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 549        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 550        struct wm8994_pdata *pdata = wm8994->pdata;
 551        int value = ucontrol->value.integer.value[0];
 552        int reg;
 553
 554        /* Don't allow on the fly reconfiguration */
 555        reg = snd_soc_read(codec, WM8994_CLOCKING_1);
 556        if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 557                return -EBUSY;
 558
 559        if (value >= pdata->num_vss_cfgs)
 560                return -EINVAL;
 561
 562        wm8994->vss_cfg = value;
 563
 564        return 0;
 565}
 566
 567static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
 568                               struct snd_ctl_elem_value *ucontrol)
 569{
 570        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 571        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 572
 573        ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
 574
 575        return 0;
 576}
 577
 578static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
 579                                   struct snd_ctl_elem_value *ucontrol)
 580{
 581        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 582        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 583        struct wm8994_pdata *pdata = wm8994->pdata;
 584        int value = ucontrol->value.integer.value[0];
 585        int reg;
 586
 587        /* Don't allow on the fly reconfiguration */
 588        reg = snd_soc_read(codec, WM8994_CLOCKING_1);
 589        if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 590                return -EBUSY;
 591
 592        if (value >= pdata->num_vss_hpf_cfgs)
 593                return -EINVAL;
 594
 595        wm8994->vss_hpf_cfg = value;
 596
 597        return 0;
 598}
 599
 600static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
 601                                   struct snd_ctl_elem_value *ucontrol)
 602{
 603        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 604        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 605
 606        ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
 607
 608        return 0;
 609}
 610
 611static int wm8958_vss_info(struct snd_kcontrol *kcontrol,
 612                           struct snd_ctl_elem_info *uinfo)
 613{
 614        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 615        uinfo->count = 1;
 616        uinfo->value.integer.min = 0;
 617        uinfo->value.integer.max = 1;
 618        return 0;
 619}
 620
 621static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
 622                          struct snd_ctl_elem_value *ucontrol)
 623{
 624        int vss = kcontrol->private_value;
 625        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 626        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 627
 628        ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
 629
 630        return 0;
 631}
 632
 633static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
 634                          struct snd_ctl_elem_value *ucontrol)
 635{
 636        int vss = kcontrol->private_value;
 637        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 638        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 639
 640        if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
 641                return 0;
 642
 643        if (ucontrol->value.integer.value[0] > 1)
 644                return -EINVAL;
 645
 646        if (!wm8994->mbc_vss)
 647                return -ENODEV;
 648
 649        if (wm8958_dsp2_busy(wm8994, vss)) {
 650                dev_dbg(codec->dev, "DSP2 active on %d already\n", vss);
 651                return -EBUSY;
 652        }
 653
 654        if (wm8994->enh_eq_ena[vss])
 655                return -EBUSY;
 656
 657        wm8994->vss_ena[vss] = ucontrol->value.integer.value[0];
 658
 659        wm8958_dsp_apply(codec, vss, wm8994->vss_ena[vss]);
 660
 661        return 0;
 662}
 663
 664
 665#define WM8958_VSS_SWITCH(xname, xval) {\
 666        .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 667        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 668        .info = wm8958_vss_info, \
 669        .get = wm8958_vss_get, .put = wm8958_vss_put, \
 670        .private_value = xval }
 671
 672static int wm8958_hpf_info(struct snd_kcontrol *kcontrol,
 673                           struct snd_ctl_elem_info *uinfo)
 674{
 675        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 676        uinfo->count = 1;
 677        uinfo->value.integer.min = 0;
 678        uinfo->value.integer.max = 1;
 679        return 0;
 680}
 681
 682static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
 683                          struct snd_ctl_elem_value *ucontrol)
 684{
 685        int hpf = kcontrol->private_value;
 686        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 687        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 688
 689        if (hpf < 3)
 690                ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3];
 691        else
 692                ucontrol->value.integer.value[0] = wm8994->hpf2_ena[hpf % 3];
 693
 694        return 0;
 695}
 696
 697static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
 698                          struct snd_ctl_elem_value *ucontrol)
 699{
 700        int hpf = kcontrol->private_value;
 701        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 702        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 703
 704        if (hpf < 3) {
 705                if (wm8994->hpf1_ena[hpf % 3] ==
 706                    ucontrol->value.integer.value[0])
 707                        return 0;
 708        } else {
 709                if (wm8994->hpf2_ena[hpf % 3] ==
 710                    ucontrol->value.integer.value[0])
 711                        return 0;
 712        }
 713
 714        if (ucontrol->value.integer.value[0] > 1)
 715                return -EINVAL;
 716
 717        if (!wm8994->mbc_vss)
 718                return -ENODEV;
 719
 720        if (wm8958_dsp2_busy(wm8994, hpf % 3)) {
 721                dev_dbg(codec->dev, "DSP2 active on %d already\n", hpf);
 722                return -EBUSY;
 723        }
 724
 725        if (wm8994->enh_eq_ena[hpf % 3])
 726                return -EBUSY;
 727
 728        if (hpf < 3)
 729                wm8994->hpf1_ena[hpf % 3] = ucontrol->value.integer.value[0];
 730        else
 731                wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0];
 732
 733        wm8958_dsp_apply(codec, hpf % 3, ucontrol->value.integer.value[0]);
 734
 735        return 0;
 736}
 737
 738#define WM8958_HPF_SWITCH(xname, xval) {\
 739        .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 740        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 741        .info = wm8958_hpf_info, \
 742        .get = wm8958_hpf_get, .put = wm8958_hpf_put, \
 743        .private_value = xval }
 744
 745static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
 746                                  struct snd_ctl_elem_value *ucontrol)
 747{
 748        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 749        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 750        struct wm8994_pdata *pdata = wm8994->pdata;
 751        int value = ucontrol->value.integer.value[0];
 752        int reg;
 753
 754        /* Don't allow on the fly reconfiguration */
 755        reg = snd_soc_read(codec, WM8994_CLOCKING_1);
 756        if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
 757                return -EBUSY;
 758
 759        if (value >= pdata->num_enh_eq_cfgs)
 760                return -EINVAL;
 761
 762        wm8994->enh_eq_cfg = value;
 763
 764        return 0;
 765}
 766
 767static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
 768                                  struct snd_ctl_elem_value *ucontrol)
 769{
 770        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 771        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 772
 773        ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
 774
 775        return 0;
 776}
 777
 778static int wm8958_enh_eq_info(struct snd_kcontrol *kcontrol,
 779                           struct snd_ctl_elem_info *uinfo)
 780{
 781        uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 782        uinfo->count = 1;
 783        uinfo->value.integer.min = 0;
 784        uinfo->value.integer.max = 1;
 785        return 0;
 786}
 787
 788static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
 789                          struct snd_ctl_elem_value *ucontrol)
 790{
 791        int eq = kcontrol->private_value;
 792        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 793        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 794
 795        ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
 796
 797        return 0;
 798}
 799
 800static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
 801                          struct snd_ctl_elem_value *ucontrol)
 802{
 803        int eq = kcontrol->private_value;
 804        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
 805        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 806
 807        if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
 808                return 0;
 809
 810        if (ucontrol->value.integer.value[0] > 1)
 811                return -EINVAL;
 812
 813        if (!wm8994->enh_eq)
 814                return -ENODEV;
 815
 816        if (wm8958_dsp2_busy(wm8994, eq)) {
 817                dev_dbg(codec->dev, "DSP2 active on %d already\n", eq);
 818                return -EBUSY;
 819        }
 820
 821        if (wm8994->mbc_ena[eq] || wm8994->vss_ena[eq] ||
 822            wm8994->hpf1_ena[eq] || wm8994->hpf2_ena[eq])
 823                return -EBUSY;
 824
 825        wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0];
 826
 827        wm8958_dsp_apply(codec, eq, ucontrol->value.integer.value[0]);
 828
 829        return 0;
 830}
 831
 832#define WM8958_ENH_EQ_SWITCH(xname, xval) {\
 833        .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
 834        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
 835        .info = wm8958_enh_eq_info, \
 836        .get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \
 837        .private_value = xval }
 838
 839static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = {
 840WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
 841WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
 842WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
 843};
 844
 845static const struct snd_kcontrol_new wm8958_vss_snd_controls[] = {
 846WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0),
 847WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1),
 848WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2),
 849WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0),
 850WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1),
 851WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2),
 852WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3),
 853WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4),
 854WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5),
 855};
 856
 857static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls[] = {
 858WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0),
 859WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1),
 860WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
 861};
 862
 863static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
 864{
 865        struct snd_soc_codec *codec = context;
 866        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 867
 868        if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) {
 869                mutex_lock(&codec->mutex);
 870                wm8994->enh_eq = fw;
 871                mutex_unlock(&codec->mutex);
 872        }
 873}
 874
 875static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
 876{
 877        struct snd_soc_codec *codec = context;
 878        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 879
 880        if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) {
 881                mutex_lock(&codec->mutex);
 882                wm8994->mbc_vss = fw;
 883                mutex_unlock(&codec->mutex);
 884        }
 885
 886        /* We can't have more than one request outstanding at once so
 887         * we daisy chain.
 888         */
 889        request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
 890                                "wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL,
 891                                codec, wm8958_enh_eq_loaded);
 892}
 893
 894static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
 895{
 896        struct snd_soc_codec *codec = context;
 897        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 898
 899        if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0)
 900                return;
 901
 902        mutex_lock(&codec->mutex);
 903        wm8994->mbc = fw;
 904        mutex_unlock(&codec->mutex);
 905
 906        /* We can't have more than one request outstanding at once so
 907         * we daisy chain.
 908         */
 909        request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
 910                                "wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL,
 911                                codec, wm8958_mbc_vss_loaded);
 912}
 913
 914void wm8958_dsp2_init(struct snd_soc_codec *codec)
 915{
 916        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 917        struct wm8994_pdata *pdata = wm8994->pdata;
 918        int ret, i;
 919
 920        wm8994->dsp_active = -1;
 921
 922        snd_soc_add_controls(codec, wm8958_mbc_snd_controls,
 923                             ARRAY_SIZE(wm8958_mbc_snd_controls));
 924        snd_soc_add_controls(codec, wm8958_vss_snd_controls,
 925                             ARRAY_SIZE(wm8958_vss_snd_controls));
 926        snd_soc_add_controls(codec, wm8958_enh_eq_snd_controls,
 927                             ARRAY_SIZE(wm8958_enh_eq_snd_controls));
 928
 929
 930        /* We don't *require* firmware and don't want to delay boot */
 931        request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
 932                                "wm8958_mbc.wfw", codec->dev, GFP_KERNEL,
 933                                codec, wm8958_mbc_loaded);
 934
 935        if (!pdata)
 936                return;
 937
 938        if (pdata->num_mbc_cfgs) {
 939                struct snd_kcontrol_new control[] = {
 940                        SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
 941                                     wm8958_get_mbc_enum, wm8958_put_mbc_enum),
 942                };
 943
 944                /* We need an array of texts for the enum API */
 945                wm8994->mbc_texts = kmalloc(sizeof(char *)
 946                                            * pdata->num_mbc_cfgs, GFP_KERNEL);
 947                if (!wm8994->mbc_texts) {
 948                        dev_err(wm8994->codec->dev,
 949                                "Failed to allocate %d MBC config texts\n",
 950                                pdata->num_mbc_cfgs);
 951                        return;
 952                }
 953
 954                for (i = 0; i < pdata->num_mbc_cfgs; i++)
 955                        wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
 956
 957                wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
 958                wm8994->mbc_enum.texts = wm8994->mbc_texts;
 959
 960                ret = snd_soc_add_controls(wm8994->codec, control, 1);
 961                if (ret != 0)
 962                        dev_err(wm8994->codec->dev,
 963                                "Failed to add MBC mode controls: %d\n", ret);
 964        }
 965
 966        if (pdata->num_vss_cfgs) {
 967                struct snd_kcontrol_new control[] = {
 968                        SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum,
 969                                     wm8958_get_vss_enum, wm8958_put_vss_enum),
 970                };
 971
 972                /* We need an array of texts for the enum API */
 973                wm8994->vss_texts = kmalloc(sizeof(char *)
 974                                            * pdata->num_vss_cfgs, GFP_KERNEL);
 975                if (!wm8994->vss_texts) {
 976                        dev_err(wm8994->codec->dev,
 977                                "Failed to allocate %d VSS config texts\n",
 978                                pdata->num_vss_cfgs);
 979                        return;
 980                }
 981
 982                for (i = 0; i < pdata->num_vss_cfgs; i++)
 983                        wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
 984
 985                wm8994->vss_enum.max = pdata->num_vss_cfgs;
 986                wm8994->vss_enum.texts = wm8994->vss_texts;
 987
 988                ret = snd_soc_add_controls(wm8994->codec, control, 1);
 989                if (ret != 0)
 990                        dev_err(wm8994->codec->dev,
 991                                "Failed to add VSS mode controls: %d\n", ret);
 992        }
 993
 994        if (pdata->num_vss_hpf_cfgs) {
 995                struct snd_kcontrol_new control[] = {
 996                        SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum,
 997                                     wm8958_get_vss_hpf_enum,
 998                                     wm8958_put_vss_hpf_enum),
 999                };
1000
1001                /* We need an array of texts for the enum API */
1002                wm8994->vss_hpf_texts = kmalloc(sizeof(char *)
1003                                                * pdata->num_vss_hpf_cfgs, GFP_KERNEL);
1004                if (!wm8994->vss_hpf_texts) {
1005                        dev_err(wm8994->codec->dev,
1006                                "Failed to allocate %d VSS HPF config texts\n",
1007                                pdata->num_vss_hpf_cfgs);
1008                        return;
1009                }
1010
1011                for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
1012                        wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
1013
1014                wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
1015                wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
1016
1017                ret = snd_soc_add_controls(wm8994->codec, control, 1);
1018                if (ret != 0)
1019                        dev_err(wm8994->codec->dev,
1020                                "Failed to add VSS HPFmode controls: %d\n",
1021                                ret);
1022        }
1023
1024        if (pdata->num_enh_eq_cfgs) {
1025                struct snd_kcontrol_new control[] = {
1026                        SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum,
1027                                     wm8958_get_enh_eq_enum,
1028                                     wm8958_put_enh_eq_enum),
1029                };
1030
1031                /* We need an array of texts for the enum API */
1032                wm8994->enh_eq_texts = kmalloc(sizeof(char *)
1033                                                * pdata->num_enh_eq_cfgs, GFP_KERNEL);
1034                if (!wm8994->enh_eq_texts) {
1035                        dev_err(wm8994->codec->dev,
1036                                "Failed to allocate %d enhanced EQ config texts\n",
1037                                pdata->num_enh_eq_cfgs);
1038                        return;
1039                }
1040
1041                for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
1042                        wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
1043
1044                wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
1045                wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
1046
1047                ret = snd_soc_add_controls(wm8994->codec, control, 1);
1048                if (ret != 0)
1049                        dev_err(wm8994->codec->dev,
1050                                "Failed to add enhanced EQ controls: %d\n",
1051                                ret);
1052        }
1053}
1054