linux/sound/soc/qcom/lpass-platform.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
   4 *
   5 * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
   6 */
   7
   8#include <linux/dma-mapping.h>
   9#include <linux/export.h>
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/platform_device.h>
  13#include <sound/pcm_params.h>
  14#include <linux/regmap.h>
  15#include <sound/soc.h>
  16#include "lpass-lpaif-reg.h"
  17#include "lpass.h"
  18
  19#define DRV_NAME "lpass-platform"
  20
  21struct lpass_pcm_data {
  22        int dma_ch;
  23        int i2s_port;
  24};
  25
  26#define LPASS_PLATFORM_BUFFER_SIZE      (24 *  2 * 1024)
  27#define LPASS_PLATFORM_PERIODS          2
  28
  29static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
  30        .info                   =       SNDRV_PCM_INFO_MMAP |
  31                                        SNDRV_PCM_INFO_MMAP_VALID |
  32                                        SNDRV_PCM_INFO_INTERLEAVED |
  33                                        SNDRV_PCM_INFO_PAUSE |
  34                                        SNDRV_PCM_INFO_RESUME,
  35        .formats                =       SNDRV_PCM_FMTBIT_S16 |
  36                                        SNDRV_PCM_FMTBIT_S24 |
  37                                        SNDRV_PCM_FMTBIT_S32,
  38        .rates                  =       SNDRV_PCM_RATE_8000_192000,
  39        .rate_min               =       8000,
  40        .rate_max               =       192000,
  41        .channels_min           =       1,
  42        .channels_max           =       8,
  43        .buffer_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE,
  44        .period_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE /
  45                                                LPASS_PLATFORM_PERIODS,
  46        .period_bytes_min       =       LPASS_PLATFORM_BUFFER_SIZE /
  47                                                LPASS_PLATFORM_PERIODS,
  48        .periods_min            =       LPASS_PLATFORM_PERIODS,
  49        .periods_max            =       LPASS_PLATFORM_PERIODS,
  50        .fifo_size              =       0,
  51};
  52
  53static int lpass_platform_alloc_dmactl_fields(struct device *dev,
  54                                         struct regmap *map)
  55{
  56        struct lpass_data *drvdata = dev_get_drvdata(dev);
  57        struct lpass_variant *v = drvdata->variant;
  58        struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
  59        int rval;
  60
  61        drvdata->rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
  62                                          GFP_KERNEL);
  63        if (drvdata->rd_dmactl == NULL)
  64                return -ENOMEM;
  65
  66        drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
  67                                          GFP_KERNEL);
  68        if (drvdata->wr_dmactl == NULL)
  69                return -ENOMEM;
  70
  71        rd_dmactl = drvdata->rd_dmactl;
  72        wr_dmactl = drvdata->wr_dmactl;
  73
  74        rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
  75                                            &v->rdma_intf, 6);
  76        if (rval)
  77                return rval;
  78
  79        return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
  80                                            &v->wrdma_intf, 6);
  81}
  82
  83static int lpass_platform_alloc_hdmidmactl_fields(struct device *dev,
  84                                         struct regmap *map)
  85{
  86        struct lpass_data *drvdata = dev_get_drvdata(dev);
  87        struct lpass_variant *v = drvdata->variant;
  88        struct lpaif_dmactl *rd_dmactl;
  89
  90        rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), GFP_KERNEL);
  91        if (rd_dmactl == NULL)
  92                return -ENOMEM;
  93
  94        drvdata->hdmi_rd_dmactl = rd_dmactl;
  95
  96        return devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->bursten,
  97                                            &v->hdmi_rdma_bursten, 8);
  98}
  99
 100static int lpass_platform_pcmops_open(struct snd_soc_component *component,
 101                                      struct snd_pcm_substream *substream)
 102{
 103        struct snd_pcm_runtime *runtime = substream->runtime;
 104        struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
 105        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 106        struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 107        struct lpass_variant *v = drvdata->variant;
 108        int ret, dma_ch, dir = substream->stream;
 109        struct lpass_pcm_data *data;
 110        struct regmap *map;
 111        unsigned int dai_id = cpu_dai->driver->id;
 112
 113        component->id = dai_id;
 114        data = kzalloc(sizeof(*data), GFP_KERNEL);
 115        if (!data)
 116                return -ENOMEM;
 117
 118        data->i2s_port = cpu_dai->driver->id;
 119        runtime->private_data = data;
 120
 121        if (v->alloc_dma_channel)
 122                dma_ch = v->alloc_dma_channel(drvdata, dir, dai_id);
 123        else
 124                dma_ch = 0;
 125
 126        if (dma_ch < 0) {
 127                kfree(data);
 128                return dma_ch;
 129        }
 130
 131        if (cpu_dai->driver->id == LPASS_DP_RX) {
 132                map = drvdata->hdmiif_map;
 133                drvdata->hdmi_substream[dma_ch] = substream;
 134        } else {
 135                map = drvdata->lpaif_map;
 136                drvdata->substream[dma_ch] = substream;
 137        }
 138        data->dma_ch = dma_ch;
 139        ret = regmap_write(map,
 140                        LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
 141        if (ret) {
 142                dev_err(soc_runtime->dev,
 143                        "error writing to rdmactl reg: %d\n", ret);
 144                return ret;
 145        }
 146        snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
 147
 148        runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
 149
 150        ret = snd_pcm_hw_constraint_integer(runtime,
 151                        SNDRV_PCM_HW_PARAM_PERIODS);
 152        if (ret < 0) {
 153                kfree(data);
 154                dev_err(soc_runtime->dev, "setting constraints failed: %d\n",
 155                        ret);
 156                return -EINVAL;
 157        }
 158
 159        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 160
 161        return 0;
 162}
 163
 164static int lpass_platform_pcmops_close(struct snd_soc_component *component,
 165                                       struct snd_pcm_substream *substream)
 166{
 167        struct snd_pcm_runtime *runtime = substream->runtime;
 168        struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
 169        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 170        struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 171        struct lpass_variant *v = drvdata->variant;
 172        struct lpass_pcm_data *data;
 173        unsigned int dai_id = cpu_dai->driver->id;
 174
 175        data = runtime->private_data;
 176        if (dai_id == LPASS_DP_RX)
 177                drvdata->hdmi_substream[data->dma_ch] = NULL;
 178        else
 179                drvdata->substream[data->dma_ch] = NULL;
 180        if (v->free_dma_channel)
 181                v->free_dma_channel(drvdata, data->dma_ch, dai_id);
 182
 183        kfree(data);
 184        return 0;
 185}
 186
 187static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 188                                           struct snd_pcm_substream *substream,
 189                                           struct snd_pcm_hw_params *params)
 190{
 191        struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
 192        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 193        struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 194        struct snd_pcm_runtime *rt = substream->runtime;
 195        struct lpass_pcm_data *pcm_data = rt->private_data;
 196        struct lpass_variant *v = drvdata->variant;
 197        snd_pcm_format_t format = params_format(params);
 198        unsigned int channels = params_channels(params);
 199        unsigned int regval;
 200        struct lpaif_dmactl *dmactl;
 201        int id, dir = substream->stream;
 202        int bitwidth;
 203        int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
 204        unsigned int dai_id = cpu_dai->driver->id;
 205
 206        if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
 207                id = pcm_data->dma_ch;
 208                if (dai_id == LPASS_DP_RX)
 209                        dmactl = drvdata->hdmi_rd_dmactl;
 210                else
 211                        dmactl = drvdata->rd_dmactl;
 212
 213        } else {
 214                dmactl = drvdata->wr_dmactl;
 215                id = pcm_data->dma_ch - v->wrdma_channel_start;
 216        }
 217
 218        bitwidth = snd_pcm_format_width(format);
 219        if (bitwidth < 0) {
 220                dev_err(soc_runtime->dev, "invalid bit width given: %d\n",
 221                                bitwidth);
 222                return bitwidth;
 223        }
 224
 225        ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4);
 226        if (ret) {
 227                dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret);
 228                return ret;
 229        }
 230
 231        ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
 232        if (ret) {
 233                dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret);
 234                return ret;
 235        }
 236
 237        switch (dai_id) {
 238        case LPASS_DP_RX:
 239                ret = regmap_fields_write(dmactl->burst8, id,
 240                                                        LPAIF_DMACTL_BURSTEN_INCR4);
 241                if (ret) {
 242                        dev_err(soc_runtime->dev, "error updating burst8en field: %d\n", ret);
 243                        return ret;
 244                }
 245                ret = regmap_fields_write(dmactl->burst16, id,
 246                                                        LPAIF_DMACTL_BURSTEN_INCR4);
 247                if (ret) {
 248                        dev_err(soc_runtime->dev, "error updating burst16en field: %d\n", ret);
 249                        return ret;
 250                }
 251                ret = regmap_fields_write(dmactl->dynburst, id,
 252                                                        LPAIF_DMACTL_BURSTEN_INCR4);
 253                if (ret) {
 254                        dev_err(soc_runtime->dev, "error updating dynbursten field: %d\n", ret);
 255                        return ret;
 256                }
 257                break;
 258        case MI2S_PRIMARY:
 259        case MI2S_SECONDARY:
 260        case MI2S_TERTIARY:
 261        case MI2S_QUATERNARY:
 262        case MI2S_QUINARY:
 263                ret = regmap_fields_write(dmactl->intf, id,
 264                                                LPAIF_DMACTL_AUDINTF(dma_port));
 265                if (ret) {
 266                        dev_err(soc_runtime->dev, "error updating audio interface field: %d\n",
 267                                        ret);
 268                        return ret;
 269                }
 270
 271                break;
 272        default:
 273                dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);
 274                break;
 275        }
 276        switch (bitwidth) {
 277        case 16:
 278                switch (channels) {
 279                case 1:
 280                case 2:
 281                        regval = LPAIF_DMACTL_WPSCNT_ONE;
 282                        break;
 283                case 4:
 284                        regval = LPAIF_DMACTL_WPSCNT_TWO;
 285                        break;
 286                case 6:
 287                        regval = LPAIF_DMACTL_WPSCNT_THREE;
 288                        break;
 289                case 8:
 290                        regval = LPAIF_DMACTL_WPSCNT_FOUR;
 291                        break;
 292                default:
 293                        dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
 294                                bitwidth, channels);
 295                        return -EINVAL;
 296                }
 297                break;
 298        case 24:
 299        case 32:
 300                switch (channels) {
 301                case 1:
 302                        regval = LPAIF_DMACTL_WPSCNT_ONE;
 303                        break;
 304                case 2:
 305                        regval = (dai_id == LPASS_DP_RX ?
 306                        LPAIF_DMACTL_WPSCNT_ONE :
 307                        LPAIF_DMACTL_WPSCNT_TWO);
 308                        break;
 309                case 4:
 310                        regval = (dai_id == LPASS_DP_RX ?
 311                        LPAIF_DMACTL_WPSCNT_TWO :
 312                        LPAIF_DMACTL_WPSCNT_FOUR);
 313                        break;
 314                case 6:
 315                        regval = (dai_id == LPASS_DP_RX ?
 316                        LPAIF_DMACTL_WPSCNT_THREE :
 317                        LPAIF_DMACTL_WPSCNT_SIX);
 318                        break;
 319                case 8:
 320                        regval = (dai_id == LPASS_DP_RX ?
 321                        LPAIF_DMACTL_WPSCNT_FOUR :
 322                        LPAIF_DMACTL_WPSCNT_EIGHT);
 323                        break;
 324                default:
 325                        dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
 326                                bitwidth, channels);
 327                        return -EINVAL;
 328                }
 329                break;
 330        default:
 331                dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
 332                        bitwidth, channels);
 333                return -EINVAL;
 334        }
 335
 336        ret = regmap_fields_write(dmactl->wpscnt, id, regval);
 337        if (ret) {
 338                dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n",
 339                        ret);
 340                return ret;
 341        }
 342
 343        return 0;
 344}
 345
 346static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
 347                                         struct snd_pcm_substream *substream)
 348{
 349        struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
 350        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 351        struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 352        struct snd_pcm_runtime *rt = substream->runtime;
 353        struct lpass_pcm_data *pcm_data = rt->private_data;
 354        struct lpass_variant *v = drvdata->variant;
 355        unsigned int reg;
 356        int ret;
 357        struct regmap *map;
 358        unsigned int dai_id = cpu_dai->driver->id;
 359
 360        if (dai_id == LPASS_DP_RX)
 361                map = drvdata->hdmiif_map;
 362        else
 363                map = drvdata->lpaif_map;
 364
 365        reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);
 366        ret = regmap_write(map, reg, 0);
 367        if (ret)
 368                dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
 369                        ret);
 370
 371        return ret;
 372}
 373
 374static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 375                                         struct snd_pcm_substream *substream)
 376{
 377        struct snd_pcm_runtime *runtime = substream->runtime;
 378        struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
 379        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 380        struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 381        struct snd_pcm_runtime *rt = substream->runtime;
 382        struct lpass_pcm_data *pcm_data = rt->private_data;
 383        struct lpass_variant *v = drvdata->variant;
 384        struct lpaif_dmactl *dmactl;
 385        struct regmap *map;
 386        int ret, id, ch, dir = substream->stream;
 387        unsigned int dai_id = cpu_dai->driver->id;
 388
 389
 390        ch = pcm_data->dma_ch;
 391        if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
 392                if (dai_id == LPASS_DP_RX) {
 393                        dmactl = drvdata->hdmi_rd_dmactl;
 394                        map = drvdata->hdmiif_map;
 395                } else {
 396                        dmactl = drvdata->rd_dmactl;
 397                        map = drvdata->lpaif_map;
 398                }
 399
 400                id = pcm_data->dma_ch;
 401        } else {
 402                dmactl = drvdata->wr_dmactl;
 403                id = pcm_data->dma_ch - v->wrdma_channel_start;
 404                map = drvdata->lpaif_map;
 405        }
 406
 407        ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
 408                                runtime->dma_addr);
 409        if (ret) {
 410                dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",
 411                        ret);
 412                return ret;
 413        }
 414
 415        ret = regmap_write(map, LPAIF_DMABUFF_REG(v, ch, dir, dai_id),
 416                        (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
 417        if (ret) {
 418                dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",
 419                        ret);
 420                return ret;
 421        }
 422
 423        ret = regmap_write(map, LPAIF_DMAPER_REG(v, ch, dir, dai_id),
 424                        (snd_pcm_lib_period_bytes(substream) >> 2) - 1);
 425        if (ret) {
 426                dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",
 427                        ret);
 428                return ret;
 429        }
 430
 431        ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
 432        if (ret) {
 433                dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
 434                        ret);
 435                return ret;
 436        }
 437
 438        return 0;
 439}
 440
 441static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 442                                         struct snd_pcm_substream *substream,
 443                                         int cmd)
 444{
 445        struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
 446        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 447        struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 448        struct snd_pcm_runtime *rt = substream->runtime;
 449        struct lpass_pcm_data *pcm_data = rt->private_data;
 450        struct lpass_variant *v = drvdata->variant;
 451        struct lpaif_dmactl *dmactl;
 452        struct regmap *map;
 453        int ret, ch, id;
 454        int dir = substream->stream;
 455        unsigned int reg_irqclr = 0, val_irqclr = 0;
 456        unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
 457        unsigned int dai_id = cpu_dai->driver->id;
 458
 459        ch = pcm_data->dma_ch;
 460        if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
 461                id = pcm_data->dma_ch;
 462                if (dai_id == LPASS_DP_RX) {
 463                        dmactl = drvdata->hdmi_rd_dmactl;
 464                        map = drvdata->hdmiif_map;
 465                } else {
 466                        dmactl = drvdata->rd_dmactl;
 467                        map = drvdata->lpaif_map;
 468                }
 469        } else {
 470                dmactl = drvdata->wr_dmactl;
 471                id = pcm_data->dma_ch - v->wrdma_channel_start;
 472                map = drvdata->lpaif_map;
 473        }
 474
 475        switch (cmd) {
 476        case SNDRV_PCM_TRIGGER_START:
 477        case SNDRV_PCM_TRIGGER_RESUME:
 478        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 479                ret = regmap_fields_write(dmactl->enable, id,
 480                                                 LPAIF_DMACTL_ENABLE_ON);
 481                if (ret) {
 482                        dev_err(soc_runtime->dev,
 483                                "error writing to rdmactl reg: %d\n", ret);
 484                        return ret;
 485                }
 486                switch (dai_id) {
 487                case LPASS_DP_RX:
 488                        ret = regmap_fields_write(dmactl->dyncclk, id,
 489                                         LPAIF_DMACTL_DYNCLK_ON);
 490                        if (ret) {
 491                                dev_err(soc_runtime->dev,
 492                                        "error writing to rdmactl reg: %d\n", ret);
 493                                return ret;
 494                        }
 495                        reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
 496                        val_irqclr = (LPAIF_IRQ_ALL(ch) |
 497                                        LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
 498                                        LPAIF_IRQ_HDMI_METADONE |
 499                                        LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
 500
 501                        reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
 502                        val_mask = (LPAIF_IRQ_ALL(ch) |
 503                                        LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
 504                                        LPAIF_IRQ_HDMI_METADONE |
 505                                        LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
 506                        val_irqen = (LPAIF_IRQ_ALL(ch) |
 507                                        LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
 508                                        LPAIF_IRQ_HDMI_METADONE |
 509                                        LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
 510                        break;
 511                case MI2S_PRIMARY:
 512                case MI2S_SECONDARY:
 513                case MI2S_TERTIARY:
 514                case MI2S_QUATERNARY:
 515                case MI2S_QUINARY:
 516                        reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
 517                        val_irqclr = LPAIF_IRQ_ALL(ch);
 518
 519
 520                        reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
 521                        val_mask = LPAIF_IRQ_ALL(ch);
 522                        val_irqen = LPAIF_IRQ_ALL(ch);
 523                        break;
 524                default:
 525                        dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
 526                        return -EINVAL;
 527                }
 528
 529                ret = regmap_write(map, reg_irqclr, val_irqclr);
 530                if (ret) {
 531                        dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret);
 532                        return ret;
 533                }
 534                ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
 535                if (ret) {
 536                        dev_err(soc_runtime->dev, "error writing to irqen reg: %d\n", ret);
 537                        return ret;
 538                }
 539                break;
 540        case SNDRV_PCM_TRIGGER_STOP:
 541        case SNDRV_PCM_TRIGGER_SUSPEND:
 542        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 543                ret = regmap_fields_write(dmactl->enable, id,
 544                                         LPAIF_DMACTL_ENABLE_OFF);
 545                if (ret) {
 546                        dev_err(soc_runtime->dev,
 547                                "error writing to rdmactl reg: %d\n", ret);
 548                        return ret;
 549                }
 550                switch (dai_id) {
 551                case LPASS_DP_RX:
 552                        ret = regmap_fields_write(dmactl->dyncclk, id,
 553                                         LPAIF_DMACTL_DYNCLK_OFF);
 554                        if (ret) {
 555                                dev_err(soc_runtime->dev,
 556                                        "error writing to rdmactl reg: %d\n", ret);
 557                                return ret;
 558                        }
 559                        reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
 560                        val_mask = (LPAIF_IRQ_ALL(ch) |
 561                                        LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
 562                                        LPAIF_IRQ_HDMI_METADONE |
 563                                        LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
 564                        val_irqen = 0;
 565                        break;
 566                case MI2S_PRIMARY:
 567                case MI2S_SECONDARY:
 568                case MI2S_TERTIARY:
 569                case MI2S_QUATERNARY:
 570                case MI2S_QUINARY:
 571                        reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
 572                        val_mask = LPAIF_IRQ_ALL(ch);
 573                        val_irqen = 0;
 574                        break;
 575                default:
 576                        dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
 577                        return -EINVAL;
 578                }
 579
 580                ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
 581                if (ret) {
 582                        dev_err(soc_runtime->dev,
 583                                "error writing to irqen reg: %d\n", ret);
 584                        return ret;
 585                }
 586                break;
 587        }
 588
 589        return 0;
 590}
 591
 592static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 593                struct snd_soc_component *component,
 594                struct snd_pcm_substream *substream)
 595{
 596        struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
 597        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 598        struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 599        struct snd_pcm_runtime *rt = substream->runtime;
 600        struct lpass_pcm_data *pcm_data = rt->private_data;
 601        struct lpass_variant *v = drvdata->variant;
 602        unsigned int base_addr, curr_addr;
 603        int ret, ch, dir = substream->stream;
 604        struct regmap *map;
 605        unsigned int dai_id = cpu_dai->driver->id;
 606
 607        if (dai_id == LPASS_DP_RX)
 608                map = drvdata->hdmiif_map;
 609        else
 610                map = drvdata->lpaif_map;
 611
 612        ch = pcm_data->dma_ch;
 613
 614        ret = regmap_read(map,
 615                        LPAIF_DMABASE_REG(v, ch, dir, dai_id), &base_addr);
 616        if (ret) {
 617                dev_err(soc_runtime->dev,
 618                        "error reading from rdmabase reg: %d\n", ret);
 619                return ret;
 620        }
 621
 622        ret = regmap_read(map,
 623                        LPAIF_DMACURR_REG(v, ch, dir, dai_id), &curr_addr);
 624        if (ret) {
 625                dev_err(soc_runtime->dev,
 626                        "error reading from rdmacurr reg: %d\n", ret);
 627                return ret;
 628        }
 629
 630        return bytes_to_frames(substream->runtime, curr_addr - base_addr);
 631}
 632
 633static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
 634                                      struct snd_pcm_substream *substream,
 635                                      struct vm_area_struct *vma)
 636{
 637        struct snd_pcm_runtime *runtime = substream->runtime;
 638
 639        return dma_mmap_coherent(component->dev, vma, runtime->dma_area,
 640                                 runtime->dma_addr, runtime->dma_bytes);
 641}
 642
 643static irqreturn_t lpass_dma_interrupt_handler(
 644                        struct snd_pcm_substream *substream,
 645                        struct lpass_data *drvdata,
 646                        int chan, u32 interrupts)
 647{
 648        struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
 649        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 650        struct lpass_variant *v = drvdata->variant;
 651        irqreturn_t ret = IRQ_NONE;
 652        int rv;
 653        unsigned int reg = 0, val = 0;
 654        struct regmap *map;
 655        unsigned int dai_id = cpu_dai->driver->id;
 656
 657        switch (dai_id) {
 658        case LPASS_DP_RX:
 659                map = drvdata->hdmiif_map;
 660                reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
 661                val = (LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
 662                LPAIF_IRQ_HDMI_METADONE |
 663                LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan));
 664        break;
 665        case MI2S_PRIMARY:
 666        case MI2S_SECONDARY:
 667        case MI2S_TERTIARY:
 668        case MI2S_QUATERNARY:
 669        case MI2S_QUINARY:
 670                map = drvdata->lpaif_map;
 671                reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
 672                val = 0;
 673        break;
 674        default:
 675        dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
 676        return -EINVAL;
 677        }
 678        if (interrupts & LPAIF_IRQ_PER(chan)) {
 679
 680                rv = regmap_write(map, reg, LPAIF_IRQ_PER(chan) | val);
 681                if (rv) {
 682                        dev_err(soc_runtime->dev,
 683                                "error writing to irqclear reg: %d\n", rv);
 684                        return IRQ_NONE;
 685                }
 686                snd_pcm_period_elapsed(substream);
 687                ret = IRQ_HANDLED;
 688        }
 689
 690        if (interrupts & LPAIF_IRQ_XRUN(chan)) {
 691                rv = regmap_write(map, reg, LPAIF_IRQ_XRUN(chan) | val);
 692                if (rv) {
 693                        dev_err(soc_runtime->dev,
 694                                "error writing to irqclear reg: %d\n", rv);
 695                        return IRQ_NONE;
 696                }
 697                dev_warn(soc_runtime->dev, "xrun warning\n");
 698                snd_pcm_stop_xrun(substream);
 699                ret = IRQ_HANDLED;
 700        }
 701
 702        if (interrupts & LPAIF_IRQ_ERR(chan)) {
 703                rv = regmap_write(map, reg, LPAIF_IRQ_ERR(chan) | val);
 704                if (rv) {
 705                        dev_err(soc_runtime->dev,
 706                                "error writing to irqclear reg: %d\n", rv);
 707                        return IRQ_NONE;
 708                }
 709                dev_err(soc_runtime->dev, "bus access error\n");
 710                snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
 711                ret = IRQ_HANDLED;
 712        }
 713
 714        if (interrupts & val) {
 715                rv = regmap_write(map, reg, val);
 716                if (rv) {
 717                        dev_err(soc_runtime->dev,
 718                        "error writing to irqclear reg: %d\n", rv);
 719                        return IRQ_NONE;
 720                }
 721                ret = IRQ_HANDLED;
 722        }
 723
 724        return ret;
 725}
 726
 727static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 728{
 729        struct lpass_data *drvdata = data;
 730        struct lpass_variant *v = drvdata->variant;
 731        unsigned int irqs;
 732        int rv, chan;
 733
 734        rv = regmap_read(drvdata->lpaif_map,
 735                        LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
 736        if (rv) {
 737                pr_err("error reading from irqstat reg: %d\n", rv);
 738                return IRQ_NONE;
 739        }
 740
 741        /* Handle per channel interrupts */
 742        for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
 743                if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
 744                        rv = lpass_dma_interrupt_handler(
 745                                                drvdata->substream[chan],
 746                                                drvdata, chan, irqs);
 747                        if (rv != IRQ_HANDLED)
 748                                return rv;
 749                }
 750        }
 751
 752        return IRQ_HANDLED;
 753}
 754
 755static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
 756{
 757        struct lpass_data *drvdata = data;
 758        struct lpass_variant *v = drvdata->variant;
 759        unsigned int irqs;
 760        int rv, chan;
 761
 762        rv = regmap_read(drvdata->hdmiif_map,
 763                        LPASS_HDMITX_APP_IRQSTAT_REG(v), &irqs);
 764        if (rv) {
 765                pr_err("error reading from irqstat reg: %d\n", rv);
 766                return IRQ_NONE;
 767        }
 768
 769        /* Handle per channel interrupts */
 770        for (chan = 0; chan < LPASS_MAX_HDMI_DMA_CHANNELS; chan++) {
 771                if (irqs & (LPAIF_IRQ_ALL(chan) | LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
 772                                LPAIF_IRQ_HDMI_METADONE |
 773                                LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan))
 774                        && drvdata->hdmi_substream[chan]) {
 775                        rv = lpass_dma_interrupt_handler(
 776                                                drvdata->hdmi_substream[chan],
 777                                                drvdata, chan, irqs);
 778                        if (rv != IRQ_HANDLED)
 779                                return rv;
 780                }
 781        }
 782
 783        return IRQ_HANDLED;
 784}
 785
 786static int lpass_platform_pcm_new(struct snd_soc_component *component,
 787                                  struct snd_soc_pcm_runtime *soc_runtime)
 788{
 789        struct snd_pcm *pcm = soc_runtime->pcm;
 790        struct snd_pcm_substream *psubstream, *csubstream;
 791        int ret = -EINVAL;
 792        size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
 793
 794        psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 795        if (psubstream) {
 796                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
 797                                        component->dev,
 798                                        size, &psubstream->dma_buffer);
 799                if (ret) {
 800                        dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
 801                        return ret;
 802                }
 803        }
 804
 805        csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
 806        if (csubstream) {
 807                ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
 808                                        component->dev,
 809                                        size, &csubstream->dma_buffer);
 810                if (ret) {
 811                        dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
 812                        if (psubstream)
 813                                snd_dma_free_pages(&psubstream->dma_buffer);
 814                        return ret;
 815                }
 816
 817        }
 818
 819        return 0;
 820}
 821
 822static void lpass_platform_pcm_free(struct snd_soc_component *component,
 823                                    struct snd_pcm *pcm)
 824{
 825        struct snd_pcm_substream *substream;
 826        int i;
 827
 828        for_each_pcm_streams(i) {
 829                substream = pcm->streams[i].substream;
 830                if (substream) {
 831                        snd_dma_free_pages(&substream->dma_buffer);
 832                        substream->dma_buffer.area = NULL;
 833                        substream->dma_buffer.addr = 0;
 834                }
 835        }
 836}
 837
 838static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
 839{
 840        struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 841        struct regmap *map;
 842        unsigned int dai_id = component->id;
 843
 844        if (dai_id == LPASS_DP_RX)
 845                map = drvdata->hdmiif_map;
 846        else
 847                map = drvdata->lpaif_map;
 848
 849        regcache_cache_only(map, true);
 850        regcache_mark_dirty(map);
 851
 852        return 0;
 853}
 854
 855static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
 856{
 857        struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 858        struct regmap *map;
 859        unsigned int dai_id = component->id;
 860
 861        if (dai_id == LPASS_DP_RX)
 862                map = drvdata->hdmiif_map;
 863        else
 864                map = drvdata->lpaif_map;
 865
 866        regcache_cache_only(map, false);
 867        return regcache_sync(map);
 868}
 869
 870
 871static const struct snd_soc_component_driver lpass_component_driver = {
 872        .name           = DRV_NAME,
 873        .open           = lpass_platform_pcmops_open,
 874        .close          = lpass_platform_pcmops_close,
 875        .hw_params      = lpass_platform_pcmops_hw_params,
 876        .hw_free        = lpass_platform_pcmops_hw_free,
 877        .prepare        = lpass_platform_pcmops_prepare,
 878        .trigger        = lpass_platform_pcmops_trigger,
 879        .pointer        = lpass_platform_pcmops_pointer,
 880        .mmap           = lpass_platform_pcmops_mmap,
 881        .pcm_construct  = lpass_platform_pcm_new,
 882        .pcm_destruct   = lpass_platform_pcm_free,
 883        .suspend                = lpass_platform_pcmops_suspend,
 884        .resume                 = lpass_platform_pcmops_resume,
 885
 886};
 887
 888int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 889{
 890        struct lpass_data *drvdata = platform_get_drvdata(pdev);
 891        struct lpass_variant *v = drvdata->variant;
 892        int ret;
 893
 894        drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
 895        if (drvdata->lpaif_irq < 0)
 896                return -ENODEV;
 897
 898        /* ensure audio hardware is disabled */
 899        ret = regmap_write(drvdata->lpaif_map,
 900                        LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
 901        if (ret) {
 902                dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
 903                return ret;
 904        }
 905
 906        ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
 907                        lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
 908                        "lpass-irq-lpaif", drvdata);
 909        if (ret) {
 910                dev_err(&pdev->dev, "irq request failed: %d\n", ret);
 911                return ret;
 912        }
 913
 914        ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,
 915                                                 drvdata->lpaif_map);
 916        if (ret) {
 917                dev_err(&pdev->dev,
 918                        "error initializing dmactl fields: %d\n", ret);
 919                return ret;
 920        }
 921
 922        if (drvdata->hdmi_port_enable) {
 923                drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
 924                if (drvdata->hdmiif_irq < 0)
 925                        return -ENODEV;
 926
 927                ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq,
 928                                lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata);
 929                if (ret) {
 930                        dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret);
 931                        return ret;
 932                }
 933                ret = regmap_write(drvdata->hdmiif_map,
 934                                LPASS_HDMITX_APP_IRQEN_REG(v), 0);
 935                if (ret) {
 936                        dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret);
 937                        return ret;
 938                }
 939
 940                ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev,
 941                                                         drvdata->hdmiif_map);
 942                if (ret) {
 943                        dev_err(&pdev->dev,
 944                                "error initializing hdmidmactl fields: %d\n", ret);
 945                        return ret;
 946                }
 947        }
 948        return devm_snd_soc_register_component(&pdev->dev,
 949                        &lpass_component_driver, NULL, 0);
 950}
 951EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
 952
 953MODULE_DESCRIPTION("QTi LPASS Platform Driver");
 954MODULE_LICENSE("GPL v2");
 955