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                u8 *virt;
 221
 222                buff = (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
 223                                                siu_stream->cur_period,
 224                                                siu_stream->period_bytes);
 225                virt = PERIOD_OFFSET(rt->dma_area,
 226                                     siu_stream->cur_period,
 227                                     siu_stream->period_bytes);
 228                count = siu_stream->period_bytes;
 229
 230                /* DMA transfer start */
 231                siu_pcm_rd_set(port_info, buff, count);
 232        } else {
 233                siu_pcm_wr_set(port_info,
 234                               (dma_addr_t)PERIOD_OFFSET(rt->dma_addr,
 235                                                siu_stream->cur_period,
 236                                                siu_stream->period_bytes),
 237                               siu_stream->period_bytes);
 238        }
 239}
 240
 241/* Capture */
 242static int siu_pcm_stmread_start(struct siu_port *port_info)
 243{
 244        struct siu_stream *siu_stream = &port_info->capture;
 245
 246        if (siu_stream->xfer_cnt > 0x1000000)
 247                return -EINVAL;
 248        if (siu_stream->rw_flg)
 249                return -EPERM;
 250
 251        /* Current period in buffer */
 252        siu_stream->cur_period = 0;
 253
 254        /* during stmread flag set */
 255        siu_stream->rw_flg = RWF_STM_RD;
 256
 257        queue_work(system_highpri_wq, &siu_stream->work);
 258
 259        return 0;
 260}
 261
 262static int siu_pcm_stmread_stop(struct siu_port *port_info)
 263{
 264        struct siu_info *info = siu_i2s_data;
 265        u32 __iomem *base = info->reg;
 266        struct siu_stream *siu_stream = &port_info->capture;
 267        struct device *dev = siu_stream->substream->pcm->card->dev;
 268        u32 stfifo;
 269
 270        if (!siu_stream->rw_flg)
 271                return -EPERM;
 272
 273        /* input FIFO disable */
 274        stfifo = siu_read32(base + SIU_STFIFO);
 275        siu_write32(base + SIU_STFIFO, stfifo & ~0x13071307);
 276        dev_dbg(dev, "%s: STFIFO %x -> %x\n", __func__,
 277                stfifo, stfifo & ~0x13071307);
 278
 279        /* during stmread flag clear */
 280        siu_stream->rw_flg = 0;
 281
 282        return 0;
 283}
 284
 285static bool filter(struct dma_chan *chan, void *secondary)
 286{
 287        struct sh_dmae_slave *param = secondary;
 288
 289        pr_debug("%s: secondary ID %d\n", __func__, param->shdma_slave.slave_id);
 290
 291        chan->private = &param->shdma_slave;
 292        return true;
 293}
 294
 295static int siu_pcm_open(struct snd_soc_component *component,
 296                        struct snd_pcm_substream *ss)
 297{
 298        /* Playback / Capture */
 299        struct siu_platform *pdata = component->dev->platform_data;
 300        struct siu_info *info = siu_i2s_data;
 301        struct siu_port *port_info = siu_port_info(ss);
 302        struct siu_stream *siu_stream;
 303        u32 port = info->port_id;
 304        struct device *dev = ss->pcm->card->dev;
 305        dma_cap_mask_t mask;
 306        struct sh_dmae_slave *param;
 307
 308        dma_cap_zero(mask);
 309        dma_cap_set(DMA_SLAVE, mask);
 310
 311        dev_dbg(dev, "%s, port=%d@%p\n", __func__, port, port_info);
 312
 313        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 314                siu_stream = &port_info->playback;
 315                param = &siu_stream->param;
 316                param->shdma_slave.slave_id = port ? pdata->dma_slave_tx_b :
 317                        pdata->dma_slave_tx_a;
 318        } else {
 319                siu_stream = &port_info->capture;
 320                param = &siu_stream->param;
 321                param->shdma_slave.slave_id = port ? pdata->dma_slave_rx_b :
 322                        pdata->dma_slave_rx_a;
 323        }
 324
 325        /* Get DMA channel */
 326        siu_stream->chan = dma_request_channel(mask, filter, param);
 327        if (!siu_stream->chan) {
 328                dev_err(dev, "DMA channel allocation failed!\n");
 329                return -EBUSY;
 330        }
 331
 332        siu_stream->substream = ss;
 333
 334        return 0;
 335}
 336
 337static int siu_pcm_close(struct snd_soc_component *component,
 338                         struct snd_pcm_substream *ss)
 339{
 340        struct siu_info *info = siu_i2s_data;
 341        struct device *dev = ss->pcm->card->dev;
 342        struct siu_port *port_info = siu_port_info(ss);
 343        struct siu_stream *siu_stream;
 344
 345        dev_dbg(dev, "%s: port=%d\n", __func__, info->port_id);
 346
 347        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 348                siu_stream = &port_info->playback;
 349        else
 350                siu_stream = &port_info->capture;
 351
 352        dma_release_channel(siu_stream->chan);
 353        siu_stream->chan = NULL;
 354
 355        siu_stream->substream = NULL;
 356
 357        return 0;
 358}
 359
 360static int siu_pcm_prepare(struct snd_soc_component *component,
 361                           struct snd_pcm_substream *ss)
 362{
 363        struct siu_info *info = siu_i2s_data;
 364        struct siu_port *port_info = siu_port_info(ss);
 365        struct device *dev = ss->pcm->card->dev;
 366        struct snd_pcm_runtime  *rt = ss->runtime;
 367        struct siu_stream *siu_stream;
 368        snd_pcm_sframes_t xfer_cnt;
 369
 370        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 371                siu_stream = &port_info->playback;
 372        else
 373                siu_stream = &port_info->capture;
 374
 375        rt = siu_stream->substream->runtime;
 376
 377        siu_stream->buf_bytes = snd_pcm_lib_buffer_bytes(ss);
 378        siu_stream->period_bytes = snd_pcm_lib_period_bytes(ss);
 379
 380        dev_dbg(dev, "%s: port=%d, %d channels, period=%u bytes\n", __func__,
 381                info->port_id, rt->channels, siu_stream->period_bytes);
 382
 383        /* We only support buffers that are multiples of the period */
 384        if (siu_stream->buf_bytes % siu_stream->period_bytes) {
 385                dev_err(dev, "%s() - buffer=%d not multiple of period=%d\n",
 386                       __func__, siu_stream->buf_bytes,
 387                       siu_stream->period_bytes);
 388                return -EINVAL;
 389        }
 390
 391        xfer_cnt = bytes_to_frames(rt, siu_stream->period_bytes);
 392        if (!xfer_cnt || xfer_cnt > 0x1000000)
 393                return -EINVAL;
 394
 395        siu_stream->format = rt->format;
 396        siu_stream->xfer_cnt = xfer_cnt;
 397
 398        dev_dbg(dev, "port=%d buf=%lx buf_bytes=%d period_bytes=%d "
 399                "format=%d channels=%d xfer_cnt=%d\n", info->port_id,
 400                (unsigned long)rt->dma_addr, siu_stream->buf_bytes,
 401                siu_stream->period_bytes,
 402                siu_stream->format, rt->channels, (int)xfer_cnt);
 403
 404        return 0;
 405}
 406
 407static int siu_pcm_trigger(struct snd_soc_component *component,
 408                           struct snd_pcm_substream *ss, int cmd)
 409{
 410        struct siu_info *info = siu_i2s_data;
 411        struct device *dev = ss->pcm->card->dev;
 412        struct siu_port *port_info = siu_port_info(ss);
 413        int ret;
 414
 415        dev_dbg(dev, "%s: port=%d@%p, cmd=%d\n", __func__,
 416                info->port_id, port_info, cmd);
 417
 418        switch (cmd) {
 419        case SNDRV_PCM_TRIGGER_START:
 420                if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 421                        ret = siu_pcm_stmwrite_start(port_info);
 422                else
 423                        ret = siu_pcm_stmread_start(port_info);
 424
 425                if (ret < 0)
 426                        dev_warn(dev, "%s: start failed on port=%d\n",
 427                                 __func__, info->port_id);
 428
 429                break;
 430        case SNDRV_PCM_TRIGGER_STOP:
 431                if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 432                        siu_pcm_stmwrite_stop(port_info);
 433                else
 434                        siu_pcm_stmread_stop(port_info);
 435                ret = 0;
 436
 437                break;
 438        default:
 439                dev_err(dev, "%s() unsupported cmd=%d\n", __func__, cmd);
 440                ret = -EINVAL;
 441        }
 442
 443        return ret;
 444}
 445
 446/*
 447 * So far only resolution of one period is supported, subject to extending the
 448 * dmangine API
 449 */
 450static snd_pcm_uframes_t
 451siu_pcm_pointer_dma(struct snd_soc_component *component,
 452                    struct snd_pcm_substream *ss)
 453{
 454        struct device *dev = ss->pcm->card->dev;
 455        struct siu_info *info = siu_i2s_data;
 456        u32 __iomem *base = info->reg;
 457        struct siu_port *port_info = siu_port_info(ss);
 458        struct snd_pcm_runtime *rt = ss->runtime;
 459        size_t ptr;
 460        struct siu_stream *siu_stream;
 461
 462        if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
 463                siu_stream = &port_info->playback;
 464        else
 465                siu_stream = &port_info->capture;
 466
 467        /*
 468         * ptr is the offset into the buffer where the dma is currently at. We
 469         * check if the dma buffer has just wrapped.
 470         */
 471        ptr = PERIOD_OFFSET(rt->dma_addr,
 472                            siu_stream->cur_period,
 473                            siu_stream->period_bytes) - rt->dma_addr;
 474
 475        dev_dbg(dev,
 476                "%s: port=%d, events %x, FSTS %x, xferred %u/%u, cookie %d\n",
 477                __func__, info->port_id, siu_read32(base + SIU_EVNTC),
 478                siu_read32(base + SIU_SBFSTS), ptr, siu_stream->buf_bytes,
 479                siu_stream->cookie);
 480
 481        if (ptr >= siu_stream->buf_bytes)
 482                ptr = 0;
 483
 484        return bytes_to_frames(ss->runtime, ptr);
 485}
 486
 487static int siu_pcm_new(struct snd_soc_component *component,
 488                       struct snd_soc_pcm_runtime *rtd)
 489{
 490        /* card->dev == socdev->dev, see snd_soc_new_pcms() */
 491        struct snd_card *card = rtd->card->snd_card;
 492        struct snd_pcm *pcm = rtd->pcm;
 493        struct siu_info *info = siu_i2s_data;
 494        struct platform_device *pdev = to_platform_device(card->dev);
 495        int ret;
 496        int i;
 497
 498        /* pdev->id selects between SIUA and SIUB */
 499        if (pdev->id < 0 || pdev->id >= SIU_PORT_NUM)
 500                return -EINVAL;
 501
 502        info->port_id = pdev->id;
 503
 504        /*
 505         * While the siu has 2 ports, only one port can be on at a time (only 1
 506         * SPB). So far all the boards using the siu had only one of the ports
 507         * wired to a codec. To simplify things, we only register one port with
 508         * alsa. In case both ports are needed, it should be changed here
 509         */
 510        for (i = pdev->id; i < pdev->id + 1; i++) {
 511                struct siu_port **port_info = &siu_ports[i];
 512
 513                ret = siu_init_port(i, port_info, card);
 514                if (ret < 0)
 515                        return ret;
 516
 517                snd_pcm_set_managed_buffer_all(pcm,
 518                                SNDRV_DMA_TYPE_DEV, card->dev,
 519                                SIU_BUFFER_BYTES_MAX, SIU_BUFFER_BYTES_MAX);
 520
 521                (*port_info)->pcm = pcm;
 522
 523                /* IO works */
 524                INIT_WORK(&(*port_info)->playback.work, siu_io_work);
 525                INIT_WORK(&(*port_info)->capture.work, siu_io_work);
 526        }
 527
 528        dev_info(card->dev, "SuperH SIU driver initialized.\n");
 529        return 0;
 530}
 531
 532static void siu_pcm_free(struct snd_soc_component *component,
 533                         struct snd_pcm *pcm)
 534{
 535        struct platform_device *pdev = to_platform_device(pcm->card->dev);
 536        struct siu_port *port_info = siu_ports[pdev->id];
 537
 538        cancel_work_sync(&port_info->capture.work);
 539        cancel_work_sync(&port_info->playback.work);
 540
 541        siu_free_port(port_info);
 542
 543        dev_dbg(pcm->card->dev, "%s\n", __func__);
 544}
 545
 546struct const snd_soc_component_driver siu_component = {
 547        .name           = DRV_NAME,
 548        .open           = siu_pcm_open,
 549        .close          = siu_pcm_close,
 550        .prepare        = siu_pcm_prepare,
 551        .trigger        = siu_pcm_trigger,
 552        .pointer        = siu_pcm_pointer_dma,
 553        .pcm_construct  = siu_pcm_new,
 554        .pcm_destruct   = siu_pcm_free,
 555};
 556EXPORT_SYMBOL_GPL(siu_component);
 557