aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sh/fsi.c
diff options
context:
space:
mode:
authorKuninori Morimoto <kuninori.morimoto.gx@renesas.com>2012-02-03 03:59:33 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-02-19 21:36:16 -0500
commit7da9ced6066c654a22836c24bae509ef323e10a8 (patch)
tree82f1a7abad998927ffdf3e93076f9ee0198a2384 /sound/soc/sh/fsi.c
parentfa2c8f401797eee814b7b9fa0b23fa6c4c3f5533 (diff)
ASoC: fsi: Add DMAEngine support
This patch supports DMAEngine to FSI driver. It supports only Tx case at this point. If platform/cpu doesn't support DMAEngine, FSI driver will use PIO transfer. Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/sh/fsi.c')
-rw-r--r--sound/soc/sh/fsi.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 13746809c27d..378cc5b056d7 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -13,8 +13,11 @@
13 */ 13 */
14 14
15#include <linux/delay.h> 15#include <linux/delay.h>
16#include <linux/dma-mapping.h>
16#include <linux/pm_runtime.h> 17#include <linux/pm_runtime.h>
17#include <linux/io.h> 18#include <linux/io.h>
19#include <linux/scatterlist.h>
20#include <linux/sh_dma.h>
18#include <linux/slab.h> 21#include <linux/slab.h>
19#include <linux/module.h> 22#include <linux/module.h>
20#include <sound/soc.h> 23#include <sound/soc.h>
@@ -53,6 +56,7 @@
53 56
54/* DO_FMT */ 57/* DO_FMT */
55/* DI_FMT */ 58/* DI_FMT */
59#define CR_BWS_MASK (0x3 << 20) /* FSI2 */
56#define CR_BWS_24 (0x0 << 20) /* FSI2 */ 60#define CR_BWS_24 (0x0 << 20) /* FSI2 */
57#define CR_BWS_16 (0x1 << 20) /* FSI2 */ 61#define CR_BWS_16 (0x1 << 20) /* FSI2 */
58#define CR_BWS_20 (0x2 << 20) /* FSI2 */ 62#define CR_BWS_20 (0x2 << 20) /* FSI2 */
@@ -68,6 +72,15 @@
68#define CR_TDM (0x4 << 4) 72#define CR_TDM (0x4 << 4)
69#define CR_TDM_D (0x5 << 4) 73#define CR_TDM_D (0x5 << 4)
70 74
75/* OUT_DMAC */
76/* IN_DMAC */
77#define VDMD_MASK (0x3 << 4)
78#define VDMD_FRONT (0x0 << 4) /* Package in front */
79#define VDMD_BACK (0x1 << 4) /* Package in back */
80#define VDMD_STREAM (0x2 << 4) /* Stream mode(16bit * 2) */
81
82#define DMA_ON (0x1 << 0)
83
71/* DOFF_CTL */ 84/* DOFF_CTL */
72/* DIFF_CTL */ 85/* DIFF_CTL */
73#define IRQ_HALF 0x00100000 86#define IRQ_HALF 0x00100000
@@ -180,6 +193,14 @@ struct fsi_stream {
180 */ 193 */
181 struct fsi_stream_handler *handler; 194 struct fsi_stream_handler *handler;
182 struct fsi_priv *priv; 195 struct fsi_priv *priv;
196
197 /*
198 * these are for DMAEngine
199 */
200 struct dma_chan *chan;
201 struct sh_dmae_slave slave; /* see fsi_handler_init() */
202 struct tasklet_struct tasklet;
203 dma_addr_t dma;
183}; 204};
184 205
185struct fsi_priv { 206struct fsi_priv {
@@ -889,6 +910,212 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
889} 910}
890 911
891/* 912/*
913 * dma data transfer handler
914 */
915static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
916{
917 struct snd_pcm_runtime *runtime = io->substream->runtime;
918 struct snd_soc_dai *dai = fsi_get_dai(io->substream);
919 enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
920 DMA_TO_DEVICE : DMA_FROM_DEVICE;
921
922 io->dma = dma_map_single(dai->dev, runtime->dma_area,
923 snd_pcm_lib_buffer_bytes(io->substream), dir);
924 return 0;
925}
926
927static int fsi_dma_quit(struct fsi_priv *fsi, struct fsi_stream *io)
928{
929 struct snd_soc_dai *dai = fsi_get_dai(io->substream);
930 enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
931 DMA_TO_DEVICE : DMA_FROM_DEVICE;
932
933 dma_unmap_single(dai->dev, io->dma,
934 snd_pcm_lib_buffer_bytes(io->substream), dir);
935 return 0;
936}
937
938static void fsi_dma_complete(void *data)
939{
940 struct fsi_stream *io = (struct fsi_stream *)data;
941 struct fsi_priv *fsi = fsi_stream_to_priv(io);
942 struct snd_pcm_runtime *runtime = io->substream->runtime;
943 struct snd_soc_dai *dai = fsi_get_dai(io->substream);
944 enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
945 DMA_TO_DEVICE : DMA_FROM_DEVICE;
946
947 dma_sync_single_for_cpu(dai->dev, io->dma,
948 samples_to_bytes(runtime, io->period_samples), dir);
949
950 io->buff_sample_pos += io->period_samples;
951 io->period_pos++;
952
953 if (io->period_pos >= runtime->periods) {
954 io->period_pos = 0;
955 io->buff_sample_pos = 0;
956 }
957
958 fsi_count_fifo_err(fsi);
959 fsi_stream_transfer(io);
960
961 snd_pcm_period_elapsed(io->substream);
962}
963
964static dma_addr_t fsi_dma_get_area(struct fsi_stream *io)
965{
966 struct snd_pcm_runtime *runtime = io->substream->runtime;
967
968 return io->dma + samples_to_bytes(runtime, io->buff_sample_pos);
969}
970
971static void fsi_dma_do_tasklet(unsigned long data)
972{
973 struct fsi_stream *io = (struct fsi_stream *)data;
974 struct fsi_priv *fsi = fsi_stream_to_priv(io);
975 struct dma_chan *chan;
976 struct snd_soc_dai *dai;
977 struct dma_async_tx_descriptor *desc;
978 struct scatterlist sg;
979 struct snd_pcm_runtime *runtime;
980 enum dma_data_direction dir;
981 dma_cookie_t cookie;
982 int is_play = fsi_stream_is_play(fsi, io);
983 int len;
984 dma_addr_t buf;
985
986 if (!fsi_stream_is_working(fsi, io))
987 return;
988
989 dai = fsi_get_dai(io->substream);
990 chan = io->chan;
991 runtime = io->substream->runtime;
992 dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
993 len = samples_to_bytes(runtime, io->period_samples);
994 buf = fsi_dma_get_area(io);
995
996 dma_sync_single_for_device(dai->dev, io->dma, len, dir);
997
998 sg_init_table(&sg, 1);
999 sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)),
1000 len , offset_in_page(buf));
1001 sg_dma_address(&sg) = buf;
1002 sg_dma_len(&sg) = len;
1003
1004 desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir,
1005 DMA_PREP_INTERRUPT |
1006 DMA_CTRL_ACK);
1007 if (!desc) {
1008 dev_err(dai->dev, "device_prep_slave_sg() fail\n");
1009 return;
1010 }
1011
1012 desc->callback = fsi_dma_complete;
1013 desc->callback_param = io;
1014
1015 cookie = desc->tx_submit(desc);
1016 if (cookie < 0) {
1017 dev_err(dai->dev, "tx_submit() fail\n");
1018 return;
1019 }
1020
1021 dma_async_issue_pending(chan);
1022
1023 /*
1024 * FIXME
1025 *
1026 * In DMAEngine case, codec and FSI cannot be started simultaneously
1027 * since FSI is using tasklet.
1028 * Therefore, in capture case, probably FSI FIFO will have got
1029 * overflow error in this point.
1030 * in that case, DMA cannot start transfer until error was cleared.
1031 */
1032 if (!is_play) {
1033 if (ERR_OVER & fsi_reg_read(fsi, DIFF_ST)) {
1034 fsi_reg_mask_set(fsi, DIFF_CTL, FIFO_CLR, FIFO_CLR);
1035 fsi_reg_write(fsi, DIFF_ST, 0);
1036 }
1037 }
1038}
1039
1040static bool fsi_dma_filter(struct dma_chan *chan, void *param)
1041{
1042 struct sh_dmae_slave *slave = param;
1043
1044 chan->private = slave;
1045
1046 return true;
1047}
1048
1049static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
1050{
1051 tasklet_schedule(&io->tasklet);
1052
1053 return 0;
1054}
1055
1056static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
1057 int start)
1058{
1059 u32 bws;
1060 u32 dma;
1061
1062 switch (io->sample_width * start) {
1063 case 2:
1064 bws = CR_BWS_16;
1065 dma = VDMD_STREAM | DMA_ON;
1066 break;
1067 case 4:
1068 bws = CR_BWS_24;
1069 dma = VDMD_BACK | DMA_ON;
1070 break;
1071 default:
1072 bws = 0;
1073 dma = 0;
1074 }
1075
1076 fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws);
1077 fsi_reg_write(fsi, OUT_DMAC, dma);
1078}
1079
1080static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
1081{
1082 dma_cap_mask_t mask;
1083
1084 dma_cap_zero(mask);
1085 dma_cap_set(DMA_SLAVE, mask);
1086
1087 io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave);
1088 if (!io->chan)
1089 return -EIO;
1090
1091 tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io);
1092
1093 return 0;
1094}
1095
1096static int fsi_dma_remove(struct fsi_priv *fsi, struct fsi_stream *io)
1097{
1098 tasklet_kill(&io->tasklet);
1099
1100 fsi_stream_stop(fsi, io);
1101
1102 if (io->chan)
1103 dma_release_channel(io->chan);
1104
1105 io->chan = NULL;
1106 return 0;
1107}
1108
1109static struct fsi_stream_handler fsi_dma_push_handler = {
1110 .init = fsi_dma_init,
1111 .quit = fsi_dma_quit,
1112 .probe = fsi_dma_probe,
1113 .transfer = fsi_dma_transfer,
1114 .remove = fsi_dma_remove,
1115 .start_stop = fsi_dma_push_start_stop,
1116};
1117
1118/*
892 * dai ops 1119 * dai ops
893 */ 1120 */
894static void fsi_fifo_init(struct fsi_priv *fsi, 1121static void fsi_fifo_init(struct fsi_priv *fsi,
@@ -1304,6 +1531,11 @@ static void fsi_handler_init(struct fsi_priv *fsi)
1304 fsi->playback.priv = fsi; 1531 fsi->playback.priv = fsi;
1305 fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */ 1532 fsi->capture.handler = &fsi_pio_pop_handler; /* default PIO */
1306 fsi->capture.priv = fsi; 1533 fsi->capture.priv = fsi;
1534
1535 if (fsi->info->tx_id) {
1536 fsi->playback.slave.slave_id = fsi->info->tx_id;
1537 fsi->playback.handler = &fsi_dma_push_handler;
1538 }
1307} 1539}
1308 1540
1309static int fsi_probe(struct platform_device *pdev) 1541static int fsi_probe(struct platform_device *pdev)