brintos

brintos / linux-shallow public Read only

0
0
Text · 14.6 KiB · f15ff36 Raw
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 = &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	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