0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/module.h>
0014 #include <linux/gfp.h>
0015 #include <linux/init.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/dma-mapping.h>
0018 #include <sound/core.h>
0019 #include <sound/pcm.h>
0020 #include <sound/pcm_params.h>
0021 #include <sound/soc.h>
0022 #include <asm/dmabrg.h>
0023
0024
0025
0026 #define BRGATXSAR 0x00
0027 #define BRGARXDAR 0x04
0028 #define BRGATXTCR 0x08
0029 #define BRGARXTCR 0x0C
0030 #define BRGACR 0x10
0031 #define BRGATXTCNT 0x14
0032 #define BRGARXTCNT 0x18
0033
0034 #define ACR_RAR (1 << 18)
0035 #define ACR_RDS (1 << 17)
0036 #define ACR_RDE (1 << 16)
0037 #define ACR_TAR (1 << 2)
0038 #define ACR_TDS (1 << 1)
0039 #define ACR_TDE (1 << 0)
0040
0041
0042 #define ACR_RAM_NONE (0 << 24)
0043 #define ACR_RAM_4BYTE (1 << 24)
0044 #define ACR_RAM_2WORD (2 << 24)
0045 #define ACR_TAM_NONE (0 << 8)
0046 #define ACR_TAM_4BYTE (1 << 8)
0047 #define ACR_TAM_2WORD (2 << 8)
0048
0049
0050 struct camelot_pcm {
0051 unsigned long mmio;
0052 unsigned int txid;
0053
0054 struct snd_pcm_substream *tx_ss;
0055 unsigned long tx_period_size;
0056 unsigned int tx_period;
0057
0058 struct snd_pcm_substream *rx_ss;
0059 unsigned long rx_period_size;
0060 unsigned int rx_period;
0061
0062 } cam_pcm_data[2] = {
0063 {
0064 .mmio = 0xFE3C0040,
0065 .txid = DMABRGIRQ_A0TXF,
0066 },
0067 {
0068 .mmio = 0xFE3C0060,
0069 .txid = DMABRGIRQ_A1TXF,
0070 },
0071 };
0072
0073 #define BRGREG(x) (*(unsigned long *)(cam->mmio + (x)))
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085 #define DMABRG_PERIOD_MIN 16 * 1024
0086 #define DMABRG_PERIOD_MAX 0x03fffffc
0087 #define DMABRG_PREALLOC_BUFFER 32 * 1024
0088 #define DMABRG_PREALLOC_BUFFER_MAX 32 * 1024
0089
0090 static const struct snd_pcm_hardware camelot_pcm_hardware = {
0091 .info = (SNDRV_PCM_INFO_MMAP |
0092 SNDRV_PCM_INFO_INTERLEAVED |
0093 SNDRV_PCM_INFO_BLOCK_TRANSFER |
0094 SNDRV_PCM_INFO_MMAP_VALID |
0095 SNDRV_PCM_INFO_BATCH),
0096 .buffer_bytes_max = DMABRG_PERIOD_MAX,
0097 .period_bytes_min = DMABRG_PERIOD_MIN,
0098 .period_bytes_max = DMABRG_PERIOD_MAX / 2,
0099 .periods_min = 2,
0100 .periods_max = 2,
0101 .fifo_size = 128,
0102 };
0103
0104 static void camelot_txdma(void *data)
0105 {
0106 struct camelot_pcm *cam = data;
0107 cam->tx_period ^= 1;
0108 snd_pcm_period_elapsed(cam->tx_ss);
0109 }
0110
0111 static void camelot_rxdma(void *data)
0112 {
0113 struct camelot_pcm *cam = data;
0114 cam->rx_period ^= 1;
0115 snd_pcm_period_elapsed(cam->rx_ss);
0116 }
0117
0118 static int camelot_pcm_open(struct snd_soc_component *component,
0119 struct snd_pcm_substream *substream)
0120 {
0121 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0122 struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
0123 int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
0124 int ret, dmairq;
0125
0126 snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware);
0127
0128
0129 dmairq = (recv) ? cam->txid + 2 : cam->txid;
0130 if (recv) {
0131 cam->rx_ss = substream;
0132 ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
0133 if (unlikely(ret)) {
0134 pr_debug("audio unit %d irqs already taken!\n",
0135 asoc_rtd_to_cpu(rtd, 0)->id);
0136 return -EBUSY;
0137 }
0138 (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
0139 } else {
0140 cam->tx_ss = substream;
0141 ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
0142 if (unlikely(ret)) {
0143 pr_debug("audio unit %d irqs already taken!\n",
0144 asoc_rtd_to_cpu(rtd, 0)->id);
0145 return -EBUSY;
0146 }
0147 (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
0148 }
0149 return 0;
0150 }
0151
0152 static int camelot_pcm_close(struct snd_soc_component *component,
0153 struct snd_pcm_substream *substream)
0154 {
0155 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0156 struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
0157 int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
0158 int dmairq;
0159
0160 dmairq = (recv) ? cam->txid + 2 : cam->txid;
0161
0162 if (recv)
0163 cam->rx_ss = NULL;
0164 else
0165 cam->tx_ss = NULL;
0166
0167 dmabrg_free_irq(dmairq + 1);
0168 dmabrg_free_irq(dmairq);
0169
0170 return 0;
0171 }
0172
0173 static int camelot_hw_params(struct snd_soc_component *component,
0174 struct snd_pcm_substream *substream,
0175 struct snd_pcm_hw_params *hw_params)
0176 {
0177 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0178 struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
0179 int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
0180
0181 if (recv) {
0182 cam->rx_period_size = params_period_bytes(hw_params);
0183 cam->rx_period = 0;
0184 } else {
0185 cam->tx_period_size = params_period_bytes(hw_params);
0186 cam->tx_period = 0;
0187 }
0188 return 0;
0189 }
0190
0191 static int camelot_prepare(struct snd_soc_component *component,
0192 struct snd_pcm_substream *substream)
0193 {
0194 struct snd_pcm_runtime *runtime = substream->runtime;
0195 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0196 struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
0197
0198 pr_debug("PCM data: addr 0x%08lx len %d\n",
0199 (u32)runtime->dma_addr, runtime->dma_bytes);
0200
0201 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
0202 BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
0203 BRGREG(BRGATXTCR) = runtime->dma_bytes;
0204 } else {
0205 BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area;
0206 BRGREG(BRGARXTCR) = runtime->dma_bytes;
0207 }
0208
0209 return 0;
0210 }
0211
0212 static inline void dmabrg_play_dma_start(struct camelot_pcm *cam)
0213 {
0214 unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
0215
0216 BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD;
0217 }
0218
0219 static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam)
0220 {
0221 unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
0222
0223 BRGREG(BRGACR) = acr | ACR_TDS;
0224 }
0225
0226 static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam)
0227 {
0228 unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
0229
0230 BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD;
0231 }
0232
0233 static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
0234 {
0235 unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
0236
0237 BRGREG(BRGACR) = acr | ACR_RDS;
0238 }
0239
0240 static int camelot_trigger(struct snd_soc_component *component,
0241 struct snd_pcm_substream *substream, int cmd)
0242 {
0243 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0244 struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
0245 int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
0246
0247 switch (cmd) {
0248 case SNDRV_PCM_TRIGGER_START:
0249 if (recv)
0250 dmabrg_rec_dma_start(cam);
0251 else
0252 dmabrg_play_dma_start(cam);
0253 break;
0254 case SNDRV_PCM_TRIGGER_STOP:
0255 if (recv)
0256 dmabrg_rec_dma_stop(cam);
0257 else
0258 dmabrg_play_dma_stop(cam);
0259 break;
0260 default:
0261 return -EINVAL;
0262 }
0263
0264 return 0;
0265 }
0266
0267 static snd_pcm_uframes_t camelot_pos(struct snd_soc_component *component,
0268 struct snd_pcm_substream *substream)
0269 {
0270 struct snd_pcm_runtime *runtime = substream->runtime;
0271 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0272 struct camelot_pcm *cam = &cam_pcm_data[asoc_rtd_to_cpu(rtd, 0)->id];
0273 int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
0274 unsigned long pos;
0275
0276
0277
0278
0279
0280
0281
0282 if (recv)
0283 pos = cam->rx_period ? cam->rx_period_size : 0;
0284 else
0285 pos = cam->tx_period ? cam->tx_period_size : 0;
0286
0287 return bytes_to_frames(runtime, pos);
0288 }
0289
0290 static int camelot_pcm_new(struct snd_soc_component *component,
0291 struct snd_soc_pcm_runtime *rtd)
0292 {
0293 struct snd_pcm *pcm = rtd->pcm;
0294
0295
0296
0297
0298 snd_pcm_set_managed_buffer_all(pcm,
0299 SNDRV_DMA_TYPE_CONTINUOUS,
0300 NULL,
0301 DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX);
0302
0303 return 0;
0304 }
0305
0306 static const struct snd_soc_component_driver sh7760_soc_component = {
0307 .open = camelot_pcm_open,
0308 .close = camelot_pcm_close,
0309 .hw_params = camelot_hw_params,
0310 .prepare = camelot_prepare,
0311 .trigger = camelot_trigger,
0312 .pointer = camelot_pos,
0313 .pcm_construct = camelot_pcm_new,
0314 };
0315
0316 static int sh7760_soc_platform_probe(struct platform_device *pdev)
0317 {
0318 return devm_snd_soc_register_component(&pdev->dev, &sh7760_soc_component,
0319 NULL, 0);
0320 }
0321
0322 static struct platform_driver sh7760_pcm_driver = {
0323 .driver = {
0324 .name = "sh7760-pcm-audio",
0325 },
0326
0327 .probe = sh7760_soc_platform_probe,
0328 };
0329
0330 module_platform_driver(sh7760_pcm_driver);
0331
0332 MODULE_LICENSE("GPL v2");
0333 MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
0334 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");