Thomas Gleixner | d2912cb | 2019-06-04 10:11:33 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0-only |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 2 | /* |
| 3 | * Copyright (C) ST-Ericsson SA 2012 |
| 4 | * |
| 5 | * Author: Ola Lilja <ola.o.lilja@stericsson.com>, |
| 6 | * Roger Nilsson <roger.xr.nilsson@stericsson.com> |
| 7 | * for ST-Ericsson. |
| 8 | * |
| 9 | * License terms: |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 10 | */ |
| 11 | |
| 12 | #include <asm/page.h> |
| 13 | |
| 14 | #include <linux/module.h> |
| 15 | #include <linux/dma-mapping.h> |
| 16 | #include <linux/dmaengine.h> |
| 17 | #include <linux/slab.h> |
Linus Walleij | 865fab6 | 2012-10-18 14:20:16 +0200 | [diff] [blame] | 18 | #include <linux/platform_data/dma-ste-dma40.h> |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 19 | |
| 20 | #include <sound/pcm.h> |
| 21 | #include <sound/pcm_params.h> |
| 22 | #include <sound/soc.h> |
| 23 | #include <sound/dmaengine_pcm.h> |
| 24 | |
| 25 | #include "ux500_msp_i2s.h" |
| 26 | #include "ux500_pcm.h" |
| 27 | |
Lars-Peter Clausen | 69b6f19 | 2013-04-03 11:02:55 +0200 | [diff] [blame] | 28 | #define UX500_PLATFORM_PERIODS_BYTES_MIN 128 |
| 29 | #define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE) |
| 30 | #define UX500_PLATFORM_PERIODS_MIN 2 |
| 31 | #define UX500_PLATFORM_PERIODS_MAX 48 |
| 32 | #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) |
| 33 | |
Lars-Peter Clausen | 22f38f7 | 2013-04-15 19:20:04 +0200 | [diff] [blame] | 34 | static const struct snd_pcm_hardware ux500_pcm_hw = { |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 35 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
| 36 | SNDRV_PCM_INFO_MMAP | |
| 37 | SNDRV_PCM_INFO_RESUME | |
| 38 | SNDRV_PCM_INFO_PAUSE, |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 39 | .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, |
| 40 | .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, |
| 41 | .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, |
| 42 | .periods_min = UX500_PLATFORM_PERIODS_MIN, |
| 43 | .periods_max = UX500_PLATFORM_PERIODS_MAX, |
| 44 | }; |
| 45 | |
Lars-Peter Clausen | 22f38f7 | 2013-04-15 19:20:04 +0200 | [diff] [blame] | 46 | static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd, |
| 47 | struct snd_pcm_substream *substream) |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 48 | { |
Kuninori Morimoto | 99396e3 | 2020-03-23 14:21:35 +0900 | [diff] [blame] | 49 | struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0); |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 50 | u16 per_data_width, mem_data_width; |
| 51 | struct stedma40_chan_cfg *dma_cfg; |
Lars-Peter Clausen | 22f38f7 | 2013-04-15 19:20:04 +0200 | [diff] [blame] | 52 | struct ux500_msp_dma_params *dma_params; |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 53 | |
Lars-Peter Clausen | 22f38f7 | 2013-04-15 19:20:04 +0200 | [diff] [blame] | 54 | dma_params = snd_soc_dai_get_dma_data(dai, substream); |
| 55 | dma_cfg = dma_params->dma_cfg; |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 56 | |
Lee Jones | 43f2e1a | 2013-05-15 11:51:57 +0200 | [diff] [blame] | 57 | mem_data_width = DMA_SLAVE_BUSWIDTH_2_BYTES; |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 58 | |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 59 | switch (dma_params->data_size) { |
| 60 | case 32: |
Lee Jones | 43f2e1a | 2013-05-15 11:51:57 +0200 | [diff] [blame] | 61 | per_data_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 62 | break; |
| 63 | case 16: |
Lee Jones | 43f2e1a | 2013-05-15 11:51:57 +0200 | [diff] [blame] | 64 | per_data_width = DMA_SLAVE_BUSWIDTH_2_BYTES; |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 65 | break; |
| 66 | case 8: |
Lee Jones | 43f2e1a | 2013-05-15 11:51:57 +0200 | [diff] [blame] | 67 | per_data_width = DMA_SLAVE_BUSWIDTH_1_BYTE; |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 68 | break; |
| 69 | default: |
Lee Jones | 43f2e1a | 2013-05-15 11:51:57 +0200 | [diff] [blame] | 70 | per_data_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 71 | } |
| 72 | |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 73 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 74 | dma_cfg->src_info.data_width = mem_data_width; |
| 75 | dma_cfg->dst_info.data_width = per_data_width; |
| 76 | } else { |
| 77 | dma_cfg->src_info.data_width = per_data_width; |
| 78 | dma_cfg->dst_info.data_width = mem_data_width; |
| 79 | } |
| 80 | |
Lars-Peter Clausen | 22f38f7 | 2013-04-15 19:20:04 +0200 | [diff] [blame] | 81 | return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg); |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 82 | } |
| 83 | |
Fabio Baltieri | eef6473 | 2013-06-12 09:57:59 +0200 | [diff] [blame] | 84 | static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream, |
| 85 | struct snd_pcm_hw_params *params, |
| 86 | struct dma_slave_config *slave_config) |
| 87 | { |
Kuninori Morimoto | 3e44c479 | 2020-07-20 10:17:44 +0900 | [diff] [blame] | 88 | struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); |
Kuninori Morimoto | 99396e3 | 2020-03-23 14:21:35 +0900 | [diff] [blame] | 89 | struct msp_i2s_platform_data *pdata = asoc_rtd_to_cpu(rtd, 0)->dev->platform_data; |
Lee Jones | f6c3775 | 2013-12-19 15:55:03 +0000 | [diff] [blame] | 90 | struct snd_dmaengine_dai_dma_data *snd_dma_params; |
| 91 | struct ux500_msp_dma_params *ste_dma_params; |
| 92 | dma_addr_t dma_addr; |
Fabio Baltieri | eef6473 | 2013-06-12 09:57:59 +0200 | [diff] [blame] | 93 | int ret; |
| 94 | |
Lee Jones | f6c3775 | 2013-12-19 15:55:03 +0000 | [diff] [blame] | 95 | if (pdata) { |
| 96 | ste_dma_params = |
Kuninori Morimoto | 99396e3 | 2020-03-23 14:21:35 +0900 | [diff] [blame] | 97 | snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); |
Lee Jones | f6c3775 | 2013-12-19 15:55:03 +0000 | [diff] [blame] | 98 | dma_addr = ste_dma_params->tx_rx_addr; |
| 99 | } else { |
| 100 | snd_dma_params = |
Kuninori Morimoto | 99396e3 | 2020-03-23 14:21:35 +0900 | [diff] [blame] | 101 | snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); |
Lee Jones | f6c3775 | 2013-12-19 15:55:03 +0000 | [diff] [blame] | 102 | dma_addr = snd_dma_params->addr; |
| 103 | } |
Fabio Baltieri | eef6473 | 2013-06-12 09:57:59 +0200 | [diff] [blame] | 104 | |
| 105 | ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config); |
| 106 | if (ret) |
| 107 | return ret; |
| 108 | |
| 109 | slave_config->dst_maxburst = 4; |
Fabio Baltieri | eef6473 | 2013-06-12 09:57:59 +0200 | [diff] [blame] | 110 | slave_config->src_maxburst = 4; |
Lee Jones | 609a305 | 2013-12-19 15:55:02 +0000 | [diff] [blame] | 111 | |
| 112 | slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; |
| 113 | slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; |
Fabio Baltieri | eef6473 | 2013-06-12 09:57:59 +0200 | [diff] [blame] | 114 | |
| 115 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
Lee Jones | f6c3775 | 2013-12-19 15:55:03 +0000 | [diff] [blame] | 116 | slave_config->dst_addr = dma_addr; |
Fabio Baltieri | eef6473 | 2013-06-12 09:57:59 +0200 | [diff] [blame] | 117 | else |
Lee Jones | f6c3775 | 2013-12-19 15:55:03 +0000 | [diff] [blame] | 118 | slave_config->src_addr = dma_addr; |
Fabio Baltieri | eef6473 | 2013-06-12 09:57:59 +0200 | [diff] [blame] | 119 | |
| 120 | return 0; |
| 121 | } |
| 122 | |
Lars-Peter Clausen | 22f38f7 | 2013-04-15 19:20:04 +0200 | [diff] [blame] | 123 | static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = { |
| 124 | .pcm_hardware = &ux500_pcm_hw, |
| 125 | .compat_request_channel = ux500_pcm_request_chan, |
| 126 | .prealloc_buffer_size = 128 * 1024, |
Fabio Baltieri | eef6473 | 2013-06-12 09:57:59 +0200 | [diff] [blame] | 127 | .prepare_slave_config = ux500_pcm_prepare_slave_config, |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 128 | }; |
| 129 | |
Lee Jones | 86a3fdf | 2013-12-19 15:55:07 +0000 | [diff] [blame] | 130 | static const struct snd_dmaengine_pcm_config ux500_dmaengine_of_pcm_config = { |
| 131 | .compat_request_channel = ux500_pcm_request_chan, |
| 132 | .prepare_slave_config = ux500_pcm_prepare_slave_config, |
| 133 | }; |
| 134 | |
Bill Pemberton | da79487 | 2012-12-07 09:26:35 -0500 | [diff] [blame] | 135 | int ux500_pcm_register_platform(struct platform_device *pdev) |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 136 | { |
Lee Jones | 86a3fdf | 2013-12-19 15:55:07 +0000 | [diff] [blame] | 137 | const struct snd_dmaengine_pcm_config *pcm_config; |
| 138 | struct device_node *np = pdev->dev.of_node; |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 139 | int ret; |
| 140 | |
Lee Jones | 86a3fdf | 2013-12-19 15:55:07 +0000 | [diff] [blame] | 141 | if (np) |
| 142 | pcm_config = &ux500_dmaengine_of_pcm_config; |
| 143 | else |
| 144 | pcm_config = &ux500_dmaengine_pcm_config; |
| 145 | |
| 146 | ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, |
Lee Jones | 86a3fdf | 2013-12-19 15:55:07 +0000 | [diff] [blame] | 147 | SND_DMAENGINE_PCM_FLAG_COMPAT); |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 148 | if (ret < 0) { |
| 149 | dev_err(&pdev->dev, |
| 150 | "%s: ERROR: Failed to register platform '%s' (%d)!\n", |
| 151 | __func__, pdev->name, ret); |
| 152 | return ret; |
| 153 | } |
| 154 | |
| 155 | return 0; |
| 156 | } |
Lee Jones | 1428c20 | 2012-11-23 13:05:41 +0000 | [diff] [blame] | 157 | EXPORT_SYMBOL_GPL(ux500_pcm_register_platform); |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 158 | |
Bill Pemberton | da79487 | 2012-12-07 09:26:35 -0500 | [diff] [blame] | 159 | int ux500_pcm_unregister_platform(struct platform_device *pdev) |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 160 | { |
Lars-Peter Clausen | 22f38f7 | 2013-04-15 19:20:04 +0200 | [diff] [blame] | 161 | snd_dmaengine_pcm_unregister(&pdev->dev); |
Ola Lilja | 01a0c11 | 2012-05-24 15:26:32 +0200 | [diff] [blame] | 162 | return 0; |
| 163 | } |
Lee Jones | 1428c20 | 2012-11-23 13:05:41 +0000 | [diff] [blame] | 164 | EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); |
Arnd Bergmann | 1783c9d | 2018-01-10 17:34:45 +0100 | [diff] [blame] | 165 | |
| 166 | MODULE_AUTHOR("Ola Lilja"); |
| 167 | MODULE_AUTHOR("Roger Nilsson"); |
| 168 | MODULE_DESCRIPTION("ASoC UX500 driver"); |
| 169 | MODULE_LICENSE("GPL v2"); |