1 /* 2 * Copyright (C) ST-Ericsson SA 2012 3 * 4 * Author: Ola Lilja <ola.o.lilja@stericsson.com>, 5 * Roger Nilsson <roger.xr.nilsson@stericsson.com> 6 * for ST-Ericsson. 7 * 8 * License terms: 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as published 12 * by the Free Software Foundation. 13 */ 14 15 #include <asm/page.h> 16 17 #include <linux/module.h> 18 #include <linux/dma-mapping.h> 19 #include <linux/dmaengine.h> 20 #include <linux/slab.h> 21 #include <linux/platform_data/dma-ste-dma40.h> 22 23 #include <sound/pcm.h> 24 #include <sound/pcm_params.h> 25 #include <sound/soc.h> 26 #include <sound/dmaengine_pcm.h> 27 28 #include "ux500_msp_i2s.h" 29 #include "ux500_pcm.h" 30 31 #define UX500_PLATFORM_MIN_RATE 8000 32 #define UX500_PLATFORM_MAX_RATE 48000 33 34 #define UX500_PLATFORM_MIN_CHANNELS 1 35 #define UX500_PLATFORM_MAX_CHANNELS 8 36 37 #define UX500_PLATFORM_PERIODS_BYTES_MIN 128 38 #define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE) 39 #define UX500_PLATFORM_PERIODS_MIN 2 40 #define UX500_PLATFORM_PERIODS_MAX 48 41 #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) 42 43 static const struct snd_pcm_hardware ux500_pcm_hw = { 44 .info = SNDRV_PCM_INFO_INTERLEAVED | 45 SNDRV_PCM_INFO_MMAP | 46 SNDRV_PCM_INFO_RESUME | 47 SNDRV_PCM_INFO_PAUSE, 48 .formats = SNDRV_PCM_FMTBIT_S16_LE | 49 SNDRV_PCM_FMTBIT_U16_LE | 50 SNDRV_PCM_FMTBIT_S16_BE | 51 SNDRV_PCM_FMTBIT_U16_BE, 52 .rates = SNDRV_PCM_RATE_KNOT, 53 .rate_min = UX500_PLATFORM_MIN_RATE, 54 .rate_max = UX500_PLATFORM_MAX_RATE, 55 .channels_min = UX500_PLATFORM_MIN_CHANNELS, 56 .channels_max = UX500_PLATFORM_MAX_CHANNELS, 57 .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, 58 .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, 59 .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, 60 .periods_min = UX500_PLATFORM_PERIODS_MIN, 61 .periods_max = UX500_PLATFORM_PERIODS_MAX, 62 }; 63 64 static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd, 65 struct snd_pcm_substream *substream) 66 { 67 struct snd_soc_dai *dai = rtd->cpu_dai; 68 struct device *dev = dai->dev; 69 u16 per_data_width, mem_data_width; 70 struct stedma40_chan_cfg *dma_cfg; 71 struct ux500_msp_dma_params *dma_params; 72 73 dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, 74 snd_pcm_stream_str(substream)); 75 76 dma_params = snd_soc_dai_get_dma_data(dai, substream); 77 dma_cfg = dma_params->dma_cfg; 78 79 mem_data_width = STEDMA40_HALFWORD_WIDTH; 80 81 switch (dma_params->data_size) { 82 case 32: 83 per_data_width = STEDMA40_WORD_WIDTH; 84 break; 85 case 16: 86 per_data_width = STEDMA40_HALFWORD_WIDTH; 87 break; 88 case 8: 89 per_data_width = STEDMA40_BYTE_WIDTH; 90 break; 91 default: 92 per_data_width = STEDMA40_WORD_WIDTH; 93 } 94 95 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 96 dma_cfg->src_info.data_width = mem_data_width; 97 dma_cfg->dst_info.data_width = per_data_width; 98 } else { 99 dma_cfg->src_info.data_width = per_data_width; 100 dma_cfg->dst_info.data_width = mem_data_width; 101 } 102 103 return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg); 104 } 105 106 static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = { 107 .pcm_hardware = &ux500_pcm_hw, 108 .compat_request_channel = ux500_pcm_request_chan, 109 .prealloc_buffer_size = 128 * 1024, 110 }; 111 112 int ux500_pcm_register_platform(struct platform_device *pdev) 113 { 114 int ret; 115 116 ret = snd_dmaengine_pcm_register(&pdev->dev, 117 &ux500_dmaengine_pcm_config, 118 SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | 119 SND_DMAENGINE_PCM_FLAG_COMPAT | 120 SND_DMAENGINE_PCM_FLAG_NO_DT); 121 if (ret < 0) { 122 dev_err(&pdev->dev, 123 "%s: ERROR: Failed to register platform '%s' (%d)!\n", 124 __func__, pdev->name, ret); 125 return ret; 126 } 127 128 return 0; 129 } 130 EXPORT_SYMBOL_GPL(ux500_pcm_register_platform); 131 132 int ux500_pcm_unregister_platform(struct platform_device *pdev) 133 { 134 snd_dmaengine_pcm_unregister(&pdev->dev); 135 return 0; 136 } 137 EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); 138