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