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