554 lines · c
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 = ¶m->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 else346 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 else369 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 else419 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 else430 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 the444 * dmangine API445 */446static snd_pcm_uframes_t447siu_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 else461 siu_stream = &port_info->capture;462 463 /*464 * ptr is the offset into the buffer where the dma is currently at. We465 * 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 1502 * SPB). So far all the boards using the siu had only one of the ports503 * wired to a codec. To simplify things, we only register one port with504 * alsa. In case both ports are needed, it should be changed here505 */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 .legacy_dai_naming = 1,552};553EXPORT_SYMBOL_GPL(siu_component);554