linux/sound/soc/sh/siu_pcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2//
   3// siu_pcm.c - ALSA driver for Renesas SH7343, SH7722 SIU peripheral.
   4//
   5// Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
   6// Copyright (C) 2006 Carlos Munoz <carlos@kenati.com>
   7
   8#include <linux/delay.h>
   9#include <linux/dma-mapping.h>
  10#include <linux/dmaengine.h>
  11#include <linux/interrupt.h>
  12#include <linux/module.h>
  13#include <linux/platform_device.h>
  14
  15#include <sound/control.h>
  16#include <sound/core.h>
  17#include <sound/pcm.h>
  18#include <sound/pcm_params.h>
  19#include <sound/soc.h>
  20
  21#include <asm/siu.h>
  22
  23#include "siu.h"
  24
  25#define DRV_NAME "siu-i2s"
  26#define GET_MAX_PERIODS(buf_bytes, period_bytes) \
  27                                ((buf_bytes) / (period_bytes))
  28#define PERIOD_OFFSET(buf_addr, period_num, period_bytes) \
  29                                ((buf_addr) + ((period_num) * (period_bytes)))
  30
  31#define RWF_STM_RD              0x01            /* Read in progress */
  32#define RWF_STM_WT              0x02            /* Write in progress */
  33
  34struct siu_port *siu_ports[SIU_PORT_NUM];
  35
  36/* transfersize is number of u32 dma transfers per period */
  37static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
  38{
  39        struct siu_info *info = siu_i2s_data;
  40        u32 __iomem *base = info->reg;
  41        struct siu_stream *siu_stream = &port_info->playback;
  42        u32 stfifo;
  43
  44        if (!siu_stream->rw_flg)
  45                return -EPERM;
  46
  47        /* output FIFO disable */
  48        stfifo = siu_read32(base + SIU_STFIFO);
  49        siu_write32(base + SIU_STFIFO, stfifo & ~0x0c180c18);
  50        pr_debug("%s: STFIFO %x -> %x\n", __func__,
  51                 stfifo, stfifo & ~0x0c180c18);
  52
  53        /* during stmwrite clear */
  54        siu_stream->rw_flg = 0;
  55
  56        return 0;
  57}
  58
  59static int siu_pcm_stmwrite_start(struct siu_port *port_info)
  60{
  61        struct siu_stream *siu_stream = &port_info->playback;
  62
  63        if (siu_stream->rw_flg)
  64                return -EPERM;
  65
  66        /* Current period in buffer */
  67        port_info->playback.cur_period = 0;
  68
  69        /* during stmwrite flag set */
  70        siu_stream->rw_flg = RWF_STM_WT;
  71
  72        /* DMA transfer start */
  73        queue_work(system_highpri_wq, &siu_stream->work);
  74
  75        return 0;
  76}
  77
  78static void siu_dma_tx_complete(void *arg)
  79{
  80        struct siu_stream *siu_stream = arg;
  81
  82        if (!siu_stream->rw_flg)
  83                return;
  84
  85        /* Update completed period count */
  86        if (++siu_stream->cur_period >=
  87            GET_MAX_PERIODS(siu_stream->buf_bytes,
  88                            siu_stream->period_bytes))
  89                siu_stream->cur_period = 0;
  90
  91        pr_debug("%s: done period #%d (%u/%u bytes), cookie %d\n",
  92                __func__, siu_stream->cur_period,
  93                siu_stream->cur_period * siu_stream->period_bytes,
  94                siu_stream->buf_bytes, siu_stream->cookie);
  95
  96        queue_work(system_highpri_wq, &siu_stream->work);
  97
  98        /* Notify alsa: a period is done */
  99        snd_pcm_period_elapsed(siu_stream->substream);
 100}
 101
 102static int siu_pcm_wr_set(struct siu_port *port_info,
 103                          dma_addr_t buff, u32 size)
 104{
 105        struct siu_info *info = siu_i2s_data;
 106        u32 __iomem *base = info->reg;
 107        struct siu_stream *siu_stream = &port_info->playback;
 108        struct snd_pcm_substream *substream = siu_stream->substream;
 109        struct device *dev = substream->pcm->card->dev;
 110        struct dma_async_tx_descriptor *desc;
 111        dma_cookie_t cookie;
 112        struct scatterlist sg;
 113        u32 stfifo;
 114
 115        sg_init_table(&sg, 1);
 116        sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
 117                    size, offset_in_page(buff));
 118        sg_dma_len(&sg) = size;
 119        sg_dma_address(&sg) = buff;
 120
 121        desc = dmaengine_prep_slave_sg(siu_stream->chan,
 122                &sg, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 123        if (!desc) {
 124                dev_err(dev, "Failed to allocate a dma descriptor\n");
 125                return -ENOMEM;
 126        }
 127
 128        desc->callback = siu_dma_tx_complete;
 129        desc->callback_param = siu_stream;
 130        cookie = dmaengine_submit(desc);
 131        if (cookie < 0) {
 132                dev_err(dev, "Failed to submit a dma transfer\n");
 133                return cookie;
 134        }
 135
 136        siu_stream->tx_desc = desc;
 137        siu_stream->cookie = cookie;
 138
 139        dma_async_issue_pending(siu_stream->chan);
 140
 141        /* only output FIFO enable */
 142        stfifo = siu_read32(base + SIU_STFIFO);
 143        siu_write32(base + SIU_STFIFO, stfifo | (port_info->stfifo & 0x0c180c18));
 144        dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
 145                stfifo, stfifo | (port_info->stfifo & 0x0c180c18));
 146
 147        return 0;
 148}
 149
 150static int siu_pcm_rd_set(struct siu_port *port_info,
 151                          dma_addr_t buff, size_t size)
 152{
 153        struct siu_info *info = siu_i2s_data;
 154        u32 __iomem *base = info->reg;
 155        struct siu_stream *siu_stream = &port_info->capture;
 156        struct snd_pcm_substream *substream = siu_stream->substream;
 157        struct device *dev = substream->pcm->card->dev;
 158        struct dma_async_tx_descriptor *desc;
 159        dma_cookie_t cookie;
 160        struct scatterlist sg;
 161        u32 stfifo;
 162
 163        dev_dbg(dev, "%s: %u@%llx\n", __func__, size, (unsigned long long)buff);
 164
 165        sg_init_table(&sg, 1);
 166        sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
 167                    size, offset_in_page(buff));
 168        sg_dma_len(&sg) = size;
 169        sg_dma_address(&sg) = buff;
 170
 171        desc = dmaengine_prep_slave_sg(siu_stream->chan,
 172                &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 173        if (!desc) {
 174                dev_err(dev, "Failed to allocate dma descriptor\n");
 175                return -ENOMEM;
 176        }
 177
 178        desc->callback = siu_dma_tx_complete;
 179        desc->callback_param = siu_stream;
 180        cookie = dmaengine_submit(desc);
 181        if (cookie < 0) {
 182                dev_err(dev, "Failed to submit dma descriptor\n");
 183                return cookie;
 184        }
 185
 186        siu_stream->tx_desc = desc;
 187        siu_stream->cookie = cookie;
 188
 189        dma_async_issue_pending(siu_stream->chan);
 190
 191        /* only input FIFO enable */
 192        stfifo = siu_read32(base + SIU_STFIFO);
 193        siu_write32(base + SIU_STFIFO, siu_read32(base + SIU_STFIFO) |
 194                    (port_info->stfifo & 0x13071307));
 195        dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
 196                stfifo, stfifo | (port_info->stfifo & 0x13071307));
 197
 198        return 0;
 199}
 200
 201static void siu_io_work(struct work_struct *work)
 202{
 203        struct siu_stream *siu_stream = container_of(work, struct siu_stream,
 204                                                     work);
 205        struct snd_pcm_substream *substream = siu_stream->substream;
 206        struct device *dev = substream->pcm->card->dev;
 207        struct snd_pcm_runtime *rt = substream->runtime;
 208        struct siu_port *port_info = siu_port_info(substream);
 209
 210        dev_dbg(dev, "%s: flags %x\n", __func__, siu_stream->rw_flg);
 211
 212        if (!siu_stream->rw_flg) {
 213                dev_dbg(dev, "%s: stream inactive\n", __func__);
 214                return;
 215        }
 216
 217        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 218                dma_addr_t buff;
 219                size_t count;
 220
 221                buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
 222                                                siu_stream->cur_period,
 223                                                siu_stream->period_bytes);
 224                count = siu_stream->period_bytes;
 225
 226                /* DMA transfer start */
 227                siu_pcm_rd_set(port_info, buff, count);
 228        } else {
 229                siu_pcm_wr_set(port_info,
 230                               (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
 231                                                siu_stream->cur_period,
 232                                                siu_stream->period_bytes),
 233                               siu_stream->period_bytes);
 234        }
 235}
 236
 237/* Capture */
 238static int siu_pcm_stmread_start(struct siu_port *port_info)
 239{
 240        struct siu_stream *siu_stream = &port_info->capture;
 241
 242        if (siu_stream->xfer_cnt > 0x1000000)
 243                return -EINVAL;
 244        if (siu_stream->rw_flg)
 245                return -EPERM;
 246
 247        /* Current period in buffer */
 248        siu_stream->cur_period = 0;
 249
 250        /* during stmread flag set */
 251        siu_stream->rw_flg = RWF_STM_RD;
 252
 253        queue_work(system_highpri_wq, &siu_stream->work);
 254
 255        return 0;
 256}
 257
 258static int siu_pcm_stmread_stop(struct siu_port *port_info)
 259{
 260        struct siu_info *info = siu_i2s_data;
 261        u32 __iomem *base = info->reg;
 262        struct siu_stream *siu_stream = &port_info->capture;
 263        struct device *dev = siu_stream->substream->pcm->card->dev;
 264        u32 stfifo;
 265
 266        if (!siu_stream->rw_flg)
 267                return -EPERM;
 268
 269        /* input FIFO disable */
 270        stfifo = siu_read32(base + SIU_STFIFO);
 271        siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307);
 272        dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
 273                stfifo, stfifo & ~0x13071307);
 274
 275        /* during stmread flag clear */
 276        siu_stream->rw_flg = 0;
 277
 278        return 0;
 279}
 280
 281static bool filter(struct dma_chan *chan, void *secondary)
 282{
 283        struct sh_dmae_slave *param = secondary;
 284
 285        pr_debug("%s: secondary ID %d\n", __func__, param->shdma_slave.slave_id);
 286
 287        chan->private = &param->shdma_slave;
 288        return true;
 289}
 290
 291static int siu_pcm_open(struct snd_soc_component *component,
 292                        struct snd_pcm_substream *ss)
 293{
 294        /* Playback / Capture */
 295        struct siu_platform *pdata = component->dev->platform_data;
 296        struct siu_info *info = siu_i2s_data;
 297        struct siu_port *port_info = siu_port_info(ss);
 298        struct siu_stream *siu_stream;
 299        u32 port = info->port_id;
 300        struct device *dev = ss->pcm->card->dev;
 301        dma_cap_mask_t mask;
 302        struct sh_dmae_slave *param;
 303
 304        dma_cap_zero(mask);
 305        dma_cap_set(DMA_SLAVE, mask);
 306
 307        dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info);
 308
 309        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 310                siu_stream = &port_info->playback;
 311                param = &siu_stream->param;
 312                param->shdma_slave.slave_id = port ? pdata->dma_slave_tx_b :
 313                        pdata->dma_slave_tx_a;
 314        } else {
 315                siu_stream = &port_info->capture;
 316                param = &siu_stream->param;
 317                param->shdma_slave.slave_id = port ? pdata->dma_slave_rx_b :
 318                        pdata->dma_slave_rx_a;
 319        }
 320
 321        /* Get DMA channel */
 322        siu_stream->chan = dma_request_channel(mask, filter, param);
 323        if (!siu_stream->chan) {
 324                dev_err(dev, "DMA channel allocation failed!\n");
 325                return -EBUSY;
 326        }
 327
 328        siu_stream->substream = ss;
 329
 330        return 0;
 331}
 332
 333static int siu_pcm_close(struct snd_soc_component *component,
 334                         struct snd_pcm_substream *ss)
 335{
 336        struct siu_info *info = siu_i2s_data;
 337        struct device *dev = ss->pcm->card->dev;
 338        struct siu_port *port_info = siu_port_info(ss);
 339        struct siu_stream *siu_stream;
 340
 341        dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
 342
 343        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 344                siu_stream = &port_info->playback;
 345        else
 346                siu_stream = &port_info->capture;
 347
 348        dma_release_channel(siu_stream->chan);
 349        siu_stream->chan = NULL;
 350
 351        siu_stream->substream = NULL;
 352
 353        return 0;
 354}
 355
 356static int siu_pcm_prepare(struct snd_soc_component *component,
 357                           struct snd_pcm_substream *ss)
 358{
 359        struct siu_info *info = siu_i2s_data;
 360        struct siu_port *port_info = siu_port_info(ss);
 361        struct device *dev = ss->pcm->card->dev;
 362        struct snd_pcm_runtime *rt;
 363        struct siu_stream *siu_stream;
 364        snd_pcm_sframes_t xfer_cnt;
 365
 366        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 367                siu_stream = &port_info->playback;
 368        else
 369                siu_stream = &port_info->capture;
 370
 371        rt = siu_stream->substream->runtime;
 372
 373        siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss);
 374        siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss);
 375
 376        dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__,
 377                info->port_id, rt->channels, siu_stream->period_bytes);
 378
 379        /* We only support buffers that are multiples of the period */
 380        if (siu_stream->buf_bytes % siu_stream->period_bytes) {
 381                dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n",
 382                       __func__, siu_stream->buf_bytes,
 383                       siu_stream->period_bytes);
 384                return -EINVAL;
 385        }
 386
 387        xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes);
 388        if (!xfer_cnt || xfer_cnt > 0x1000000)
 389                return -EINVAL;
 390
 391        siu_stream->format = rt->format;
 392        siu_stream->xfer_cnt = xfer_cnt;
 393
 394        dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d "
 395                "format=%d channels=%d xfer_cnt=%d\n", info->port_id,
 396                (unsigned long)rt->dma_addr, siu_stream->buf_bytes,
 397                siu_stream->period_bytes,
 398                siu_stream->format, rt->channels, (int)xfer_cnt);
 399
 400        return 0;
 401}
 402
 403static int siu_pcm_trigger(struct snd_soc_component *component,
 404                           struct snd_pcm_substream *ss, int cmd)
 405{
 406        struct siu_info *info = siu_i2s_data;
 407        struct device *dev = ss->pcm->card->dev;
 408        struct siu_port *port_info = siu_port_info(ss);
 409        int ret;
 410
 411        dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__,
 412                info->port_id, port_info, cmd);
 413
 414        switch (cmd) {
 415        case SNDRV_PCM_TRIGGER_START:
 416                if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 417                        ret = siu_pcm_stmwrite_start(port_info);
 418                else
 419                        ret = siu_pcm_stmread_start(port_info);
 420
 421                if (ret < 0)
 422                        dev_warn(dev, "%s: start failed on port=%d\n",
 423                                 __func__, info->port_id);
 424
 425                break;
 426        case SNDRV_PCM_TRIGGER_STOP:
 427                if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 428                        siu_pcm_stmwrite_stop(port_info);
 429                else
 430                        siu_pcm_stmread_stop(port_info);
 431                ret = 0;
 432
 433                break;
 434        default:
 435                dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd);
 436                ret = -EINVAL;
 437        }
 438
 439        return ret;
 440}
 441
 442/*
 443 * So far only resolution of one period is supported, subject to extending the
 444 * dmangine API
 445 */
 446static snd_pcm_uframes_t
 447siu_pcm_pointer_dma(struct snd_soc_component *component,
 448                    struct snd_pcm_substream *ss)
 449{
 450        struct device *dev = ss->pcm->card->dev;
 451        struct siu_info *info = siu_i2s_data;
 452        u32 __iomem *base = info->reg;
 453        struct siu_port *port_info = siu_port_info(ss);
 454        struct snd_pcm_runtime *rt = ss->runtime;
 455        size_t ptr;
 456        struct siu_stream *siu_stream;
 457
 458        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 459                siu_stream = &port_info->playback;
 460        else
 461                siu_stream = &port_info->capture;
 462
 463        /*
 464         * ptr is the offset into the buffer where the dma is currently at. We
 465         * check if the dma buffer has just wrapped.
 466         */
 467        ptr = PERIOD_OFFSET(rt->dma_addr,
 468                            siu_stream->cur_period,
 469                            siu_stream->period_bytes) - rt->dma_addr;
 470
 471        dev_dbg(dev,
 472                "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n",
 473                __func__, info->port_id, siu_read32(base + SIU_EVNTC),
 474                siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes,
 475                siu_stream->cookie);
 476
 477        if (ptr >= siu_stream->buf_bytes)
 478                ptr = 0;
 479
 480        return bytes_to_frames(ss->runtime, ptr);
 481}
 482
 483static int siu_pcm_new(struct snd_soc_component *component,
 484                       struct snd_soc_pcm_runtime *rtd)
 485{
 486        /* card->dev == socdev->dev, see snd_soc_new_pcms() */
 487        struct snd_card *card = rtd->card->snd_card;
 488        struct snd_pcm *pcm = rtd->pcm;
 489        struct siu_info *info = siu_i2s_data;
 490        struct platform_device *pdev = to_platform_device(card->dev);
 491        int ret;
 492        int i;
 493
 494        /* pdev->id selects between SIUA and SIUB */
 495        if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM)
 496                return -EINVAL;
 497
 498        info->port_id = pdev->id;
 499
 500        /*
 501         * While the siu has 2 ports, only one port can be on at a time (only 1
 502         * SPB). So far all the boards using the siu had only one of the ports
 503         * wired to a codec. To simplify things, we only register one port with
 504         * alsa. In case both ports are needed, it should be changed here
 505         */
 506        for (i = pdev->id; i < pdev->id + 1; i++) {
 507                struct siu_port **port_info = &siu_ports[i];
 508
 509                ret = siu_init_port(i, port_info, card);
 510                if (ret < 0)
 511                        return ret;
 512
 513                snd_pcm_set_managed_buffer_all(pcm,
 514                                SNDRV_DMA_TYPE_DEV, card->dev,
 515                                SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX);
 516
 517                (*port_info)->pcm = pcm;
 518
 519                /* IO works */
 520                INIT_WORK(&(*port_info)->playback.work, siu_io_work);
 521                INIT_WORK(&(*port_info)->capture.work, siu_io_work);
 522        }
 523
 524        dev_info(card->dev, "SuperH SIU driver initialized.\n");
 525        return 0;
 526}
 527
 528static void siu_pcm_free(struct snd_soc_component *component,
 529                         struct snd_pcm *pcm)
 530{
 531        struct platform_device *pdev = to_platform_device(pcm->card->dev);
 532        struct siu_port *port_info = siu_ports[pdev->id];
 533
 534        cancel_work_sync(&port_info->capture.work);
 535        cancel_work_sync(&port_info->playback.work);
 536
 537        siu_free_port(port_info);
 538
 539        dev_dbg(pcm->card->dev, "%s\n", __func__);
 540}
 541
 542const struct snd_soc_component_driver siu_component = {
 543        .name           = DRV_NAME,
 544        .open           = siu_pcm_open,
 545        .close          = siu_pcm_close,
 546        .prepare        = siu_pcm_prepare,
 547        .trigger        = siu_pcm_trigger,
 548        .pointer        = siu_pcm_pointer_dma,
 549        .pcm_construct  = siu_pcm_new,
 550        .pcm_destruct   = siu_pcm_free,
 551};
 552EXPORT_SYMBOL_GPL(siu_component);
 553