18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Freescale DMA ALSA SoC PCM driver 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Author: Timur Tabi <timur@freescale.com> 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Copyright 2007-2010 Freescale Semiconductor, Inc. 88c2ecf20Sopenharmony_ci// 98c2ecf20Sopenharmony_ci// This driver implements ASoC support for the Elo DMA controller, which is 108c2ecf20Sopenharmony_ci// the DMA controller on Freescale 83xx, 85xx, and 86xx SOCs. In ALSA terms, 118c2ecf20Sopenharmony_ci// the PCM driver is what handles the DMA buffer. 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/gfp.h> 208c2ecf20Sopenharmony_ci#include <linux/of_address.h> 218c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 228c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 238c2ecf20Sopenharmony_ci#include <linux/list.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <sound/core.h> 278c2ecf20Sopenharmony_ci#include <sound/pcm.h> 288c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 298c2ecf20Sopenharmony_ci#include <sound/soc.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <asm/io.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "fsl_dma.h" 348c2ecf20Sopenharmony_ci#include "fsl_ssi.h" /* For the offset of stx0 and srx0 */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define DRV_NAME "fsl_dma" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * The formats that the DMA controller supports, which is anything 408c2ecf20Sopenharmony_ci * that is 8, 16, or 32 bits. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci#define FSLDMA_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ 438c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U8 | \ 448c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | \ 458c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_BE | \ 468c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE | \ 478c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_BE | \ 488c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 498c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_BE | \ 508c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_LE | \ 518c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U24_BE | \ 528c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE | \ 538c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_BE | \ 548c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U32_LE | \ 558c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U32_BE) 568c2ecf20Sopenharmony_cistruct dma_object { 578c2ecf20Sopenharmony_ci struct snd_soc_component_driver dai; 588c2ecf20Sopenharmony_ci dma_addr_t ssi_stx_phys; 598c2ecf20Sopenharmony_ci dma_addr_t ssi_srx_phys; 608c2ecf20Sopenharmony_ci unsigned int ssi_fifo_depth; 618c2ecf20Sopenharmony_ci struct ccsr_dma_channel __iomem *channel; 628c2ecf20Sopenharmony_ci unsigned int irq; 638c2ecf20Sopenharmony_ci bool assigned; 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* 678c2ecf20Sopenharmony_ci * The number of DMA links to use. Two is the bare minimum, but if you 688c2ecf20Sopenharmony_ci * have really small links you might need more. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci#define NUM_DMA_LINKS 2 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/** fsl_dma_private: p-substream DMA data 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * Each substream has a 1-to-1 association with a DMA channel. 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * The link[] array is first because it needs to be aligned on a 32-byte 778c2ecf20Sopenharmony_ci * boundary, so putting it first will ensure alignment without padding the 788c2ecf20Sopenharmony_ci * structure. 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * @link[]: array of link descriptors 818c2ecf20Sopenharmony_ci * @dma_channel: pointer to the DMA channel's registers 828c2ecf20Sopenharmony_ci * @irq: IRQ for this DMA channel 838c2ecf20Sopenharmony_ci * @substream: pointer to the substream object, needed by the ISR 848c2ecf20Sopenharmony_ci * @ssi_sxx_phys: bus address of the STX or SRX register to use 858c2ecf20Sopenharmony_ci * @ld_buf_phys: physical address of the LD buffer 868c2ecf20Sopenharmony_ci * @current_link: index into link[] of the link currently being processed 878c2ecf20Sopenharmony_ci * @dma_buf_phys: physical address of the DMA buffer 888c2ecf20Sopenharmony_ci * @dma_buf_next: physical address of the next period to process 898c2ecf20Sopenharmony_ci * @dma_buf_end: physical address of the byte after the end of the DMA 908c2ecf20Sopenharmony_ci * @buffer period_size: the size of a single period 918c2ecf20Sopenharmony_ci * @num_periods: the number of periods in the DMA buffer 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_cistruct fsl_dma_private { 948c2ecf20Sopenharmony_ci struct fsl_dma_link_descriptor link[NUM_DMA_LINKS]; 958c2ecf20Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel; 968c2ecf20Sopenharmony_ci unsigned int irq; 978c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 988c2ecf20Sopenharmony_ci dma_addr_t ssi_sxx_phys; 998c2ecf20Sopenharmony_ci unsigned int ssi_fifo_depth; 1008c2ecf20Sopenharmony_ci dma_addr_t ld_buf_phys; 1018c2ecf20Sopenharmony_ci unsigned int current_link; 1028c2ecf20Sopenharmony_ci dma_addr_t dma_buf_phys; 1038c2ecf20Sopenharmony_ci dma_addr_t dma_buf_next; 1048c2ecf20Sopenharmony_ci dma_addr_t dma_buf_end; 1058c2ecf20Sopenharmony_ci size_t period_size; 1068c2ecf20Sopenharmony_ci unsigned int num_periods; 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/** 1108c2ecf20Sopenharmony_ci * fsl_dma_hardare: define characteristics of the PCM hardware. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * The PCM hardware is the Freescale DMA controller. This structure defines 1138c2ecf20Sopenharmony_ci * the capabilities of that hardware. 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * Since the sampling rate and data format are not controlled by the DMA 1168c2ecf20Sopenharmony_ci * controller, we specify no limits for those values. The only exception is 1178c2ecf20Sopenharmony_ci * period_bytes_min, which is set to a reasonably low value to prevent the 1188c2ecf20Sopenharmony_ci * DMA controller from generating too many interrupts per second. 1198c2ecf20Sopenharmony_ci * 1208c2ecf20Sopenharmony_ci * Since each link descriptor has a 32-bit byte count field, we set 1218c2ecf20Sopenharmony_ci * period_bytes_max to the largest 32-bit number. We also have no maximum 1228c2ecf20Sopenharmony_ci * number of periods. 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * Note that we specify SNDRV_PCM_INFO_JOINT_DUPLEX here, but only because a 1258c2ecf20Sopenharmony_ci * limitation in the SSI driver requires the sample rates for playback and 1268c2ecf20Sopenharmony_ci * capture to be the same. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware fsl_dma_hardware = { 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 1318c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP | 1328c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 1338c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_JOINT_DUPLEX | 1348c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE, 1358c2ecf20Sopenharmony_ci .formats = FSLDMA_PCM_FORMATS, 1368c2ecf20Sopenharmony_ci .period_bytes_min = 512, /* A reasonable limit */ 1378c2ecf20Sopenharmony_ci .period_bytes_max = (u32) -1, 1388c2ecf20Sopenharmony_ci .periods_min = NUM_DMA_LINKS, 1398c2ecf20Sopenharmony_ci .periods_max = (unsigned int) -1, 1408c2ecf20Sopenharmony_ci .buffer_bytes_max = 128 * 1024, /* A reasonable limit */ 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/** 1448c2ecf20Sopenharmony_ci * fsl_dma_abort_stream: tell ALSA that the DMA transfer has aborted 1458c2ecf20Sopenharmony_ci * 1468c2ecf20Sopenharmony_ci * This function should be called by the ISR whenever the DMA controller 1478c2ecf20Sopenharmony_ci * halts data transfer. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistatic void fsl_dma_abort_stream(struct snd_pcm_substream *substream) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci snd_pcm_stop_xrun(substream); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/** 1558c2ecf20Sopenharmony_ci * fsl_dma_update_pointers - update LD pointers to point to the next period 1568c2ecf20Sopenharmony_ci * 1578c2ecf20Sopenharmony_ci * As each period is completed, this function changes the link 1588c2ecf20Sopenharmony_ci * descriptor pointers for that period to point to the next period. 1598c2ecf20Sopenharmony_ci */ 1608c2ecf20Sopenharmony_cistatic void fsl_dma_update_pointers(struct fsl_dma_private *dma_private) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct fsl_dma_link_descriptor *link = 1638c2ecf20Sopenharmony_ci &dma_private->link[dma_private->current_link]; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Update our link descriptors to point to the next period. On a 36-bit 1668c2ecf20Sopenharmony_ci * system, we also need to update the ESAD bits. We also set (keep) the 1678c2ecf20Sopenharmony_ci * snoop bits. See the comments in fsl_dma_hw_params() about snooping. 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ci if (dma_private->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 1708c2ecf20Sopenharmony_ci link->source_addr = cpu_to_be32(dma_private->dma_buf_next); 1718c2ecf20Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT 1728c2ecf20Sopenharmony_ci link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | 1738c2ecf20Sopenharmony_ci upper_32_bits(dma_private->dma_buf_next)); 1748c2ecf20Sopenharmony_ci#endif 1758c2ecf20Sopenharmony_ci } else { 1768c2ecf20Sopenharmony_ci link->dest_addr = cpu_to_be32(dma_private->dma_buf_next); 1778c2ecf20Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT 1788c2ecf20Sopenharmony_ci link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | 1798c2ecf20Sopenharmony_ci upper_32_bits(dma_private->dma_buf_next)); 1808c2ecf20Sopenharmony_ci#endif 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* Update our variables for next time */ 1848c2ecf20Sopenharmony_ci dma_private->dma_buf_next += dma_private->period_size; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (dma_private->dma_buf_next >= dma_private->dma_buf_end) 1878c2ecf20Sopenharmony_ci dma_private->dma_buf_next = dma_private->dma_buf_phys; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (++dma_private->current_link >= NUM_DMA_LINKS) 1908c2ecf20Sopenharmony_ci dma_private->current_link = 0; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/** 1948c2ecf20Sopenharmony_ci * fsl_dma_isr: interrupt handler for the DMA controller 1958c2ecf20Sopenharmony_ci * 1968c2ecf20Sopenharmony_ci * @irq: IRQ of the DMA channel 1978c2ecf20Sopenharmony_ci * @dev_id: pointer to the dma_private structure for this DMA channel 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistatic irqreturn_t fsl_dma_isr(int irq, void *dev_id) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct fsl_dma_private *dma_private = dev_id; 2028c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream = dma_private->substream; 2038c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2048c2ecf20Sopenharmony_ci struct device *dev = rtd->dev; 2058c2ecf20Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; 2068c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 2078c2ecf20Sopenharmony_ci u32 sr, sr2 = 0; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* We got an interrupt, so read the status register to see what we 2108c2ecf20Sopenharmony_ci were interrupted for. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_ci sr = in_be32(&dma_channel->sr); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (sr & CCSR_DMA_SR_TE) { 2158c2ecf20Sopenharmony_ci dev_err(dev, "dma transmit error\n"); 2168c2ecf20Sopenharmony_ci fsl_dma_abort_stream(substream); 2178c2ecf20Sopenharmony_ci sr2 |= CCSR_DMA_SR_TE; 2188c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (sr & CCSR_DMA_SR_CH) 2228c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (sr & CCSR_DMA_SR_PE) { 2258c2ecf20Sopenharmony_ci dev_err(dev, "dma programming error\n"); 2268c2ecf20Sopenharmony_ci fsl_dma_abort_stream(substream); 2278c2ecf20Sopenharmony_ci sr2 |= CCSR_DMA_SR_PE; 2288c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (sr & CCSR_DMA_SR_EOLNI) { 2328c2ecf20Sopenharmony_ci sr2 |= CCSR_DMA_SR_EOLNI; 2338c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (sr & CCSR_DMA_SR_CB) 2378c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (sr & CCSR_DMA_SR_EOSI) { 2408c2ecf20Sopenharmony_ci /* Tell ALSA we completed a period. */ 2418c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(substream); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* 2448c2ecf20Sopenharmony_ci * Update our link descriptors to point to the next period. We 2458c2ecf20Sopenharmony_ci * only need to do this if the number of periods is not equal to 2468c2ecf20Sopenharmony_ci * the number of links. 2478c2ecf20Sopenharmony_ci */ 2488c2ecf20Sopenharmony_ci if (dma_private->num_periods != NUM_DMA_LINKS) 2498c2ecf20Sopenharmony_ci fsl_dma_update_pointers(dma_private); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci sr2 |= CCSR_DMA_SR_EOSI; 2528c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (sr & CCSR_DMA_SR_EOLSI) { 2568c2ecf20Sopenharmony_ci sr2 |= CCSR_DMA_SR_EOLSI; 2578c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Clear the bits that we set */ 2618c2ecf20Sopenharmony_ci if (sr2) 2628c2ecf20Sopenharmony_ci out_be32(&dma_channel->sr, sr2); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return ret; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/** 2688c2ecf20Sopenharmony_ci * fsl_dma_new: initialize this PCM driver. 2698c2ecf20Sopenharmony_ci * 2708c2ecf20Sopenharmony_ci * This function is called when the codec driver calls snd_soc_new_pcms(), 2718c2ecf20Sopenharmony_ci * once for each .dai_link in the machine driver's snd_soc_card 2728c2ecf20Sopenharmony_ci * structure. 2738c2ecf20Sopenharmony_ci * 2748c2ecf20Sopenharmony_ci * snd_dma_alloc_pages() is just a front-end to dma_alloc_coherent(), which 2758c2ecf20Sopenharmony_ci * (currently) always allocates the DMA buffer in lowmem, even if GFP_HIGHMEM 2768c2ecf20Sopenharmony_ci * is specified. Therefore, any DMA buffers we allocate will always be in low 2778c2ecf20Sopenharmony_ci * memory, but we support for 36-bit physical addresses anyway. 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * Regardless of where the memory is actually allocated, since the device can 2808c2ecf20Sopenharmony_ci * technically DMA to any 36-bit address, we do need to set the DMA mask to 36. 2818c2ecf20Sopenharmony_ci */ 2828c2ecf20Sopenharmony_cistatic int fsl_dma_new(struct snd_soc_component *component, 2838c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct snd_card *card = rtd->card->snd_card; 2868c2ecf20Sopenharmony_ci struct snd_pcm *pcm = rtd->pcm; 2878c2ecf20Sopenharmony_ci int ret; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(36)); 2908c2ecf20Sopenharmony_ci if (ret) 2918c2ecf20Sopenharmony_ci return ret; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* Some codecs have separate DAIs for playback and capture, so we 2948c2ecf20Sopenharmony_ci * should allocate a DMA buffer only for the streams that are valid. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 2988c2ecf20Sopenharmony_ci ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, 2998c2ecf20Sopenharmony_ci fsl_dma_hardware.buffer_bytes_max, 3008c2ecf20Sopenharmony_ci &pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); 3018c2ecf20Sopenharmony_ci if (ret) { 3028c2ecf20Sopenharmony_ci dev_err(card->dev, "can't alloc playback dma buffer\n"); 3038c2ecf20Sopenharmony_ci return ret; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 3088c2ecf20Sopenharmony_ci ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, 3098c2ecf20Sopenharmony_ci fsl_dma_hardware.buffer_bytes_max, 3108c2ecf20Sopenharmony_ci &pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->dma_buffer); 3118c2ecf20Sopenharmony_ci if (ret) { 3128c2ecf20Sopenharmony_ci dev_err(card->dev, "can't alloc capture dma buffer\n"); 3138c2ecf20Sopenharmony_ci snd_dma_free_pages(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->dma_buffer); 3148c2ecf20Sopenharmony_ci return ret; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * fsl_dma_open: open a new substream. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * Each substream has its own DMA buffer. 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * ALSA divides the DMA buffer into N periods. We create NUM_DMA_LINKS link 3278c2ecf20Sopenharmony_ci * descriptors that ping-pong from one period to the next. For example, if 3288c2ecf20Sopenharmony_ci * there are six periods and two link descriptors, this is how they look 3298c2ecf20Sopenharmony_ci * before playback starts: 3308c2ecf20Sopenharmony_ci * 3318c2ecf20Sopenharmony_ci * The last link descriptor 3328c2ecf20Sopenharmony_ci * ____________ points back to the first 3338c2ecf20Sopenharmony_ci * | | 3348c2ecf20Sopenharmony_ci * V | 3358c2ecf20Sopenharmony_ci * ___ ___ | 3368c2ecf20Sopenharmony_ci * | |->| |->| 3378c2ecf20Sopenharmony_ci * |___| |___| 3388c2ecf20Sopenharmony_ci * | | 3398c2ecf20Sopenharmony_ci * | | 3408c2ecf20Sopenharmony_ci * V V 3418c2ecf20Sopenharmony_ci * _________________________________________ 3428c2ecf20Sopenharmony_ci * | | | | | | | The DMA buffer is 3438c2ecf20Sopenharmony_ci * | | | | | | | divided into 6 parts 3448c2ecf20Sopenharmony_ci * |______|______|______|______|______|______| 3458c2ecf20Sopenharmony_ci * 3468c2ecf20Sopenharmony_ci * and here's how they look after the first period is finished playing: 3478c2ecf20Sopenharmony_ci * 3488c2ecf20Sopenharmony_ci * ____________ 3498c2ecf20Sopenharmony_ci * | | 3508c2ecf20Sopenharmony_ci * V | 3518c2ecf20Sopenharmony_ci * ___ ___ | 3528c2ecf20Sopenharmony_ci * | |->| |->| 3538c2ecf20Sopenharmony_ci * |___| |___| 3548c2ecf20Sopenharmony_ci * | | 3558c2ecf20Sopenharmony_ci * |______________ 3568c2ecf20Sopenharmony_ci * | | 3578c2ecf20Sopenharmony_ci * V V 3588c2ecf20Sopenharmony_ci * _________________________________________ 3598c2ecf20Sopenharmony_ci * | | | | | | | 3608c2ecf20Sopenharmony_ci * | | | | | | | 3618c2ecf20Sopenharmony_ci * |______|______|______|______|______|______| 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * The first link descriptor now points to the third period. The DMA 3648c2ecf20Sopenharmony_ci * controller is currently playing the second period. When it finishes, it 3658c2ecf20Sopenharmony_ci * will jump back to the first descriptor and play the third period. 3668c2ecf20Sopenharmony_ci * 3678c2ecf20Sopenharmony_ci * There are four reasons we do this: 3688c2ecf20Sopenharmony_ci * 3698c2ecf20Sopenharmony_ci * 1. The only way to get the DMA controller to automatically restart the 3708c2ecf20Sopenharmony_ci * transfer when it gets to the end of the buffer is to use chaining 3718c2ecf20Sopenharmony_ci * mode. Basic direct mode doesn't offer that feature. 3728c2ecf20Sopenharmony_ci * 2. We need to receive an interrupt at the end of every period. The DMA 3738c2ecf20Sopenharmony_ci * controller can generate an interrupt at the end of every link transfer 3748c2ecf20Sopenharmony_ci * (aka segment). Making each period into a DMA segment will give us the 3758c2ecf20Sopenharmony_ci * interrupts we need. 3768c2ecf20Sopenharmony_ci * 3. By creating only two link descriptors, regardless of the number of 3778c2ecf20Sopenharmony_ci * periods, we do not need to reallocate the link descriptors if the 3788c2ecf20Sopenharmony_ci * number of periods changes. 3798c2ecf20Sopenharmony_ci * 4. All of the audio data is still stored in a single, contiguous DMA 3808c2ecf20Sopenharmony_ci * buffer, which is what ALSA expects. We're just dividing it into 3818c2ecf20Sopenharmony_ci * contiguous parts, and creating a link descriptor for each one. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_cistatic int fsl_dma_open(struct snd_soc_component *component, 3848c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 3878c2ecf20Sopenharmony_ci struct device *dev = component->dev; 3888c2ecf20Sopenharmony_ci struct dma_object *dma = 3898c2ecf20Sopenharmony_ci container_of(component->driver, struct dma_object, dai); 3908c2ecf20Sopenharmony_ci struct fsl_dma_private *dma_private; 3918c2ecf20Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel; 3928c2ecf20Sopenharmony_ci dma_addr_t ld_buf_phys; 3938c2ecf20Sopenharmony_ci u64 temp_link; /* Pointer to next link descriptor */ 3948c2ecf20Sopenharmony_ci u32 mr; 3958c2ecf20Sopenharmony_ci unsigned int channel; 3968c2ecf20Sopenharmony_ci int ret = 0; 3978c2ecf20Sopenharmony_ci unsigned int i; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* 4008c2ecf20Sopenharmony_ci * Reject any DMA buffer whose size is not a multiple of the period 4018c2ecf20Sopenharmony_ci * size. We need to make sure that the DMA buffer can be evenly divided 4028c2ecf20Sopenharmony_ci * into periods. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci ret = snd_pcm_hw_constraint_integer(runtime, 4058c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 4068c2ecf20Sopenharmony_ci if (ret < 0) { 4078c2ecf20Sopenharmony_ci dev_err(dev, "invalid buffer size\n"); 4088c2ecf20Sopenharmony_ci return ret; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci channel = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (dma->assigned) { 4148c2ecf20Sopenharmony_ci dev_err(dev, "dma channel already assigned\n"); 4158c2ecf20Sopenharmony_ci return -EBUSY; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci dma_private = dma_alloc_coherent(dev, sizeof(struct fsl_dma_private), 4198c2ecf20Sopenharmony_ci &ld_buf_phys, GFP_KERNEL); 4208c2ecf20Sopenharmony_ci if (!dma_private) { 4218c2ecf20Sopenharmony_ci dev_err(dev, "can't allocate dma private data\n"); 4228c2ecf20Sopenharmony_ci return -ENOMEM; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 4258c2ecf20Sopenharmony_ci dma_private->ssi_sxx_phys = dma->ssi_stx_phys; 4268c2ecf20Sopenharmony_ci else 4278c2ecf20Sopenharmony_ci dma_private->ssi_sxx_phys = dma->ssi_srx_phys; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci dma_private->ssi_fifo_depth = dma->ssi_fifo_depth; 4308c2ecf20Sopenharmony_ci dma_private->dma_channel = dma->channel; 4318c2ecf20Sopenharmony_ci dma_private->irq = dma->irq; 4328c2ecf20Sopenharmony_ci dma_private->substream = substream; 4338c2ecf20Sopenharmony_ci dma_private->ld_buf_phys = ld_buf_phys; 4348c2ecf20Sopenharmony_ci dma_private->dma_buf_phys = substream->dma_buffer.addr; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci ret = request_irq(dma_private->irq, fsl_dma_isr, 0, "fsldma-audio", 4378c2ecf20Sopenharmony_ci dma_private); 4388c2ecf20Sopenharmony_ci if (ret) { 4398c2ecf20Sopenharmony_ci dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", 4408c2ecf20Sopenharmony_ci dma_private->irq, ret); 4418c2ecf20Sopenharmony_ci dma_free_coherent(dev, sizeof(struct fsl_dma_private), 4428c2ecf20Sopenharmony_ci dma_private, dma_private->ld_buf_phys); 4438c2ecf20Sopenharmony_ci return ret; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci dma->assigned = true; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 4498c2ecf20Sopenharmony_ci snd_soc_set_runtime_hwparams(substream, &fsl_dma_hardware); 4508c2ecf20Sopenharmony_ci runtime->private_data = dma_private; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* Program the fixed DMA controller parameters */ 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci dma_channel = dma_private->dma_channel; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci temp_link = dma_private->ld_buf_phys + 4578c2ecf20Sopenharmony_ci sizeof(struct fsl_dma_link_descriptor); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci for (i = 0; i < NUM_DMA_LINKS; i++) { 4608c2ecf20Sopenharmony_ci dma_private->link[i].next = cpu_to_be64(temp_link); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci temp_link += sizeof(struct fsl_dma_link_descriptor); 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci /* The last link descriptor points to the first */ 4658c2ecf20Sopenharmony_ci dma_private->link[i - 1].next = cpu_to_be64(dma_private->ld_buf_phys); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* Tell the DMA controller where the first link descriptor is */ 4688c2ecf20Sopenharmony_ci out_be32(&dma_channel->clndar, 4698c2ecf20Sopenharmony_ci CCSR_DMA_CLNDAR_ADDR(dma_private->ld_buf_phys)); 4708c2ecf20Sopenharmony_ci out_be32(&dma_channel->eclndar, 4718c2ecf20Sopenharmony_ci CCSR_DMA_ECLNDAR_ADDR(dma_private->ld_buf_phys)); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* The manual says the BCR must be clear before enabling EMP */ 4748c2ecf20Sopenharmony_ci out_be32(&dma_channel->bcr, 0); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* 4778c2ecf20Sopenharmony_ci * Program the mode register for interrupts, external master control, 4788c2ecf20Sopenharmony_ci * and source/destination hold. Also clear the Channel Abort bit. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ci mr = in_be32(&dma_channel->mr) & 4818c2ecf20Sopenharmony_ci ~(CCSR_DMA_MR_CA | CCSR_DMA_MR_DAHE | CCSR_DMA_MR_SAHE); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* 4848c2ecf20Sopenharmony_ci * We want External Master Start and External Master Pause enabled, 4858c2ecf20Sopenharmony_ci * because the SSI is controlling the DMA controller. We want the DMA 4868c2ecf20Sopenharmony_ci * controller to be set up in advance, and then we signal only the SSI 4878c2ecf20Sopenharmony_ci * to start transferring. 4888c2ecf20Sopenharmony_ci * 4898c2ecf20Sopenharmony_ci * We want End-Of-Segment Interrupts enabled, because this will generate 4908c2ecf20Sopenharmony_ci * an interrupt at the end of each segment (each link descriptor 4918c2ecf20Sopenharmony_ci * represents one segment). Each DMA segment is the same thing as an 4928c2ecf20Sopenharmony_ci * ALSA period, so this is how we get an interrupt at the end of every 4938c2ecf20Sopenharmony_ci * period. 4948c2ecf20Sopenharmony_ci * 4958c2ecf20Sopenharmony_ci * We want Error Interrupt enabled, so that we can get an error if 4968c2ecf20Sopenharmony_ci * the DMA controller is mis-programmed somehow. 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_ci mr |= CCSR_DMA_MR_EOSIE | CCSR_DMA_MR_EIE | CCSR_DMA_MR_EMP_EN | 4998c2ecf20Sopenharmony_ci CCSR_DMA_MR_EMS_EN; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* For playback, we want the destination address to be held. For 5028c2ecf20Sopenharmony_ci capture, set the source address to be held. */ 5038c2ecf20Sopenharmony_ci mr |= (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 5048c2ecf20Sopenharmony_ci CCSR_DMA_MR_DAHE : CCSR_DMA_MR_SAHE; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci out_be32(&dma_channel->mr, mr); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci/** 5128c2ecf20Sopenharmony_ci * fsl_dma_hw_params: continue initializing the DMA links 5138c2ecf20Sopenharmony_ci * 5148c2ecf20Sopenharmony_ci * This function obtains hardware parameters about the opened stream and 5158c2ecf20Sopenharmony_ci * programs the DMA controller accordingly. 5168c2ecf20Sopenharmony_ci * 5178c2ecf20Sopenharmony_ci * One drawback of big-endian is that when copying integers of different 5188c2ecf20Sopenharmony_ci * sizes to a fixed-sized register, the address to which the integer must be 5198c2ecf20Sopenharmony_ci * copied is dependent on the size of the integer. 5208c2ecf20Sopenharmony_ci * 5218c2ecf20Sopenharmony_ci * For example, if P is the address of a 32-bit register, and X is a 32-bit 5228c2ecf20Sopenharmony_ci * integer, then X should be copied to address P. However, if X is a 16-bit 5238c2ecf20Sopenharmony_ci * integer, then it should be copied to P+2. If X is an 8-bit register, 5248c2ecf20Sopenharmony_ci * then it should be copied to P+3. 5258c2ecf20Sopenharmony_ci * 5268c2ecf20Sopenharmony_ci * So for playback of 8-bit samples, the DMA controller must transfer single 5278c2ecf20Sopenharmony_ci * bytes from the DMA buffer to the last byte of the STX0 register, i.e. 5288c2ecf20Sopenharmony_ci * offset by 3 bytes. For 16-bit samples, the offset is two bytes. 5298c2ecf20Sopenharmony_ci * 5308c2ecf20Sopenharmony_ci * For 24-bit samples, the offset is 1 byte. However, the DMA controller 5318c2ecf20Sopenharmony_ci * does not support 3-byte copies (the DAHTS register supports only 1, 2, 4, 5328c2ecf20Sopenharmony_ci * and 8 bytes at a time). So we do not support packed 24-bit samples. 5338c2ecf20Sopenharmony_ci * 24-bit data must be padded to 32 bits. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_cistatic int fsl_dma_hw_params(struct snd_soc_component *component, 5368c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 5378c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 5408c2ecf20Sopenharmony_ci struct fsl_dma_private *dma_private = runtime->private_data; 5418c2ecf20Sopenharmony_ci struct device *dev = component->dev; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* Number of bits per sample */ 5448c2ecf20Sopenharmony_ci unsigned int sample_bits = 5458c2ecf20Sopenharmony_ci snd_pcm_format_physical_width(params_format(hw_params)); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* Number of bytes per frame */ 5488c2ecf20Sopenharmony_ci unsigned int sample_bytes = sample_bits / 8; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Bus address of SSI STX register */ 5518c2ecf20Sopenharmony_ci dma_addr_t ssi_sxx_phys = dma_private->ssi_sxx_phys; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* Size of the DMA buffer, in bytes */ 5548c2ecf20Sopenharmony_ci size_t buffer_size = params_buffer_bytes(hw_params); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Number of bytes per period */ 5578c2ecf20Sopenharmony_ci size_t period_size = params_period_bytes(hw_params); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Pointer to next period */ 5608c2ecf20Sopenharmony_ci dma_addr_t temp_addr = substream->dma_buffer.addr; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Pointer to DMA controller */ 5638c2ecf20Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci u32 mr; /* DMA Mode Register */ 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci unsigned int i; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* Initialize our DMA tracking variables */ 5708c2ecf20Sopenharmony_ci dma_private->period_size = period_size; 5718c2ecf20Sopenharmony_ci dma_private->num_periods = params_periods(hw_params); 5728c2ecf20Sopenharmony_ci dma_private->dma_buf_end = dma_private->dma_buf_phys + buffer_size; 5738c2ecf20Sopenharmony_ci dma_private->dma_buf_next = dma_private->dma_buf_phys + 5748c2ecf20Sopenharmony_ci (NUM_DMA_LINKS * period_size); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (dma_private->dma_buf_next >= dma_private->dma_buf_end) 5778c2ecf20Sopenharmony_ci /* This happens if the number of periods == NUM_DMA_LINKS */ 5788c2ecf20Sopenharmony_ci dma_private->dma_buf_next = dma_private->dma_buf_phys; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci mr = in_be32(&dma_channel->mr) & ~(CCSR_DMA_MR_BWC_MASK | 5818c2ecf20Sopenharmony_ci CCSR_DMA_MR_SAHTS_MASK | CCSR_DMA_MR_DAHTS_MASK); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* Due to a quirk of the SSI's STX register, the target address 5848c2ecf20Sopenharmony_ci * for the DMA operations depends on the sample size. So we calculate 5858c2ecf20Sopenharmony_ci * that offset here. While we're at it, also tell the DMA controller 5868c2ecf20Sopenharmony_ci * how much data to transfer per sample. 5878c2ecf20Sopenharmony_ci */ 5888c2ecf20Sopenharmony_ci switch (sample_bits) { 5898c2ecf20Sopenharmony_ci case 8: 5908c2ecf20Sopenharmony_ci mr |= CCSR_DMA_MR_DAHTS_1 | CCSR_DMA_MR_SAHTS_1; 5918c2ecf20Sopenharmony_ci ssi_sxx_phys += 3; 5928c2ecf20Sopenharmony_ci break; 5938c2ecf20Sopenharmony_ci case 16: 5948c2ecf20Sopenharmony_ci mr |= CCSR_DMA_MR_DAHTS_2 | CCSR_DMA_MR_SAHTS_2; 5958c2ecf20Sopenharmony_ci ssi_sxx_phys += 2; 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci case 32: 5988c2ecf20Sopenharmony_ci mr |= CCSR_DMA_MR_DAHTS_4 | CCSR_DMA_MR_SAHTS_4; 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci default: 6018c2ecf20Sopenharmony_ci /* We should never get here */ 6028c2ecf20Sopenharmony_ci dev_err(dev, "unsupported sample size %u\n", sample_bits); 6038c2ecf20Sopenharmony_ci return -EINVAL; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* 6078c2ecf20Sopenharmony_ci * BWC determines how many bytes are sent/received before the DMA 6088c2ecf20Sopenharmony_ci * controller checks the SSI to see if it needs to stop. BWC should 6098c2ecf20Sopenharmony_ci * always be a multiple of the frame size, so that we always transmit 6108c2ecf20Sopenharmony_ci * whole frames. Each frame occupies two slots in the FIFO. The 6118c2ecf20Sopenharmony_ci * parameter for CCSR_DMA_MR_BWC() is rounded down the next power of two 6128c2ecf20Sopenharmony_ci * (MR[BWC] can only represent even powers of two). 6138c2ecf20Sopenharmony_ci * 6148c2ecf20Sopenharmony_ci * To simplify the process, we set BWC to the largest value that is 6158c2ecf20Sopenharmony_ci * less than or equal to the FIFO watermark. For playback, this ensures 6168c2ecf20Sopenharmony_ci * that we transfer the maximum amount without overrunning the FIFO. 6178c2ecf20Sopenharmony_ci * For capture, this ensures that we transfer the maximum amount without 6188c2ecf20Sopenharmony_ci * underrunning the FIFO. 6198c2ecf20Sopenharmony_ci * 6208c2ecf20Sopenharmony_ci * f = SSI FIFO depth 6218c2ecf20Sopenharmony_ci * w = SSI watermark value (which equals f - 2) 6228c2ecf20Sopenharmony_ci * b = DMA bandwidth count (in bytes) 6238c2ecf20Sopenharmony_ci * s = sample size (in bytes, which equals frame_size * 2) 6248c2ecf20Sopenharmony_ci * 6258c2ecf20Sopenharmony_ci * For playback, we never transmit more than the transmit FIFO 6268c2ecf20Sopenharmony_ci * watermark, otherwise we might write more data than the FIFO can hold. 6278c2ecf20Sopenharmony_ci * The watermark is equal to the FIFO depth minus two. 6288c2ecf20Sopenharmony_ci * 6298c2ecf20Sopenharmony_ci * For capture, two equations must hold: 6308c2ecf20Sopenharmony_ci * w > f - (b / s) 6318c2ecf20Sopenharmony_ci * w >= b / s 6328c2ecf20Sopenharmony_ci * 6338c2ecf20Sopenharmony_ci * So, b > 2 * s, but b must also be <= s * w. To simplify, we set 6348c2ecf20Sopenharmony_ci * b = s * w, which is equal to 6358c2ecf20Sopenharmony_ci * (dma_private->ssi_fifo_depth - 2) * sample_bytes. 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_ci mr |= CCSR_DMA_MR_BWC((dma_private->ssi_fifo_depth - 2) * sample_bytes); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci out_be32(&dma_channel->mr, mr); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci for (i = 0; i < NUM_DMA_LINKS; i++) { 6428c2ecf20Sopenharmony_ci struct fsl_dma_link_descriptor *link = &dma_private->link[i]; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci link->count = cpu_to_be32(period_size); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* The snoop bit tells the DMA controller whether it should tell 6478c2ecf20Sopenharmony_ci * the ECM to snoop during a read or write to an address. For 6488c2ecf20Sopenharmony_ci * audio, we use DMA to transfer data between memory and an I/O 6498c2ecf20Sopenharmony_ci * device (the SSI's STX0 or SRX0 register). Snooping is only 6508c2ecf20Sopenharmony_ci * needed if there is a cache, so we need to snoop memory 6518c2ecf20Sopenharmony_ci * addresses only. For playback, that means we snoop the source 6528c2ecf20Sopenharmony_ci * but not the destination. For capture, we snoop the 6538c2ecf20Sopenharmony_ci * destination but not the source. 6548c2ecf20Sopenharmony_ci * 6558c2ecf20Sopenharmony_ci * Note that failing to snoop properly is unlikely to cause 6568c2ecf20Sopenharmony_ci * cache incoherency if the period size is larger than the 6578c2ecf20Sopenharmony_ci * size of L1 cache. This is because filling in one period will 6588c2ecf20Sopenharmony_ci * flush out the data for the previous period. So if you 6598c2ecf20Sopenharmony_ci * increased period_bytes_min to a large enough size, you might 6608c2ecf20Sopenharmony_ci * get more performance by not snooping, and you'll still be 6618c2ecf20Sopenharmony_ci * okay. You'll need to update fsl_dma_update_pointers() also. 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 6648c2ecf20Sopenharmony_ci link->source_addr = cpu_to_be32(temp_addr); 6658c2ecf20Sopenharmony_ci link->source_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | 6668c2ecf20Sopenharmony_ci upper_32_bits(temp_addr)); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci link->dest_addr = cpu_to_be32(ssi_sxx_phys); 6698c2ecf20Sopenharmony_ci link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP | 6708c2ecf20Sopenharmony_ci upper_32_bits(ssi_sxx_phys)); 6718c2ecf20Sopenharmony_ci } else { 6728c2ecf20Sopenharmony_ci link->source_addr = cpu_to_be32(ssi_sxx_phys); 6738c2ecf20Sopenharmony_ci link->source_attr = cpu_to_be32(CCSR_DMA_ATR_NOSNOOP | 6748c2ecf20Sopenharmony_ci upper_32_bits(ssi_sxx_phys)); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci link->dest_addr = cpu_to_be32(temp_addr); 6778c2ecf20Sopenharmony_ci link->dest_attr = cpu_to_be32(CCSR_DMA_ATR_SNOOP | 6788c2ecf20Sopenharmony_ci upper_32_bits(temp_addr)); 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci temp_addr += period_size; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci/** 6888c2ecf20Sopenharmony_ci * fsl_dma_pointer: determine the current position of the DMA transfer 6898c2ecf20Sopenharmony_ci * 6908c2ecf20Sopenharmony_ci * This function is called by ALSA when ALSA wants to know where in the 6918c2ecf20Sopenharmony_ci * stream buffer the hardware currently is. 6928c2ecf20Sopenharmony_ci * 6938c2ecf20Sopenharmony_ci * For playback, the SAR register contains the physical address of the most 6948c2ecf20Sopenharmony_ci * recent DMA transfer. For capture, the value is in the DAR register. 6958c2ecf20Sopenharmony_ci * 6968c2ecf20Sopenharmony_ci * The base address of the buffer is stored in the source_addr field of the 6978c2ecf20Sopenharmony_ci * first link descriptor. 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t fsl_dma_pointer(struct snd_soc_component *component, 7008c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 7038c2ecf20Sopenharmony_ci struct fsl_dma_private *dma_private = runtime->private_data; 7048c2ecf20Sopenharmony_ci struct device *dev = component->dev; 7058c2ecf20Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; 7068c2ecf20Sopenharmony_ci dma_addr_t position; 7078c2ecf20Sopenharmony_ci snd_pcm_uframes_t frames; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* Obtain the current DMA pointer, but don't read the ESAD bits if we 7108c2ecf20Sopenharmony_ci * only have 32-bit DMA addresses. This function is typically called 7118c2ecf20Sopenharmony_ci * in interrupt context, so we need to optimize it. 7128c2ecf20Sopenharmony_ci */ 7138c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 7148c2ecf20Sopenharmony_ci position = in_be32(&dma_channel->sar); 7158c2ecf20Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT 7168c2ecf20Sopenharmony_ci position |= (u64)(in_be32(&dma_channel->satr) & 7178c2ecf20Sopenharmony_ci CCSR_DMA_ATR_ESAD_MASK) << 32; 7188c2ecf20Sopenharmony_ci#endif 7198c2ecf20Sopenharmony_ci } else { 7208c2ecf20Sopenharmony_ci position = in_be32(&dma_channel->dar); 7218c2ecf20Sopenharmony_ci#ifdef CONFIG_PHYS_64BIT 7228c2ecf20Sopenharmony_ci position |= (u64)(in_be32(&dma_channel->datr) & 7238c2ecf20Sopenharmony_ci CCSR_DMA_ATR_ESAD_MASK) << 32; 7248c2ecf20Sopenharmony_ci#endif 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* 7288c2ecf20Sopenharmony_ci * When capture is started, the SSI immediately starts to fill its FIFO. 7298c2ecf20Sopenharmony_ci * This means that the DMA controller is not started until the FIFO is 7308c2ecf20Sopenharmony_ci * full. However, ALSA calls this function before that happens, when 7318c2ecf20Sopenharmony_ci * MR.DAR is still zero. In this case, just return zero to indicate 7328c2ecf20Sopenharmony_ci * that nothing has been received yet. 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ci if (!position) 7358c2ecf20Sopenharmony_ci return 0; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if ((position < dma_private->dma_buf_phys) || 7388c2ecf20Sopenharmony_ci (position > dma_private->dma_buf_end)) { 7398c2ecf20Sopenharmony_ci dev_err(dev, "dma pointer is out of range, halting stream\n"); 7408c2ecf20Sopenharmony_ci return SNDRV_PCM_POS_XRUN; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci frames = bytes_to_frames(runtime, position - dma_private->dma_buf_phys); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* 7468c2ecf20Sopenharmony_ci * If the current address is just past the end of the buffer, wrap it 7478c2ecf20Sopenharmony_ci * around. 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_ci if (frames == runtime->buffer_size) 7508c2ecf20Sopenharmony_ci frames = 0; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci return frames; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci/** 7568c2ecf20Sopenharmony_ci * fsl_dma_hw_free: release resources allocated in fsl_dma_hw_params() 7578c2ecf20Sopenharmony_ci * 7588c2ecf20Sopenharmony_ci * Release the resources allocated in fsl_dma_hw_params() and de-program the 7598c2ecf20Sopenharmony_ci * registers. 7608c2ecf20Sopenharmony_ci * 7618c2ecf20Sopenharmony_ci * This function can be called multiple times. 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_cistatic int fsl_dma_hw_free(struct snd_soc_component *component, 7648c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 7678c2ecf20Sopenharmony_ci struct fsl_dma_private *dma_private = runtime->private_data; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (dma_private) { 7708c2ecf20Sopenharmony_ci struct ccsr_dma_channel __iomem *dma_channel; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci dma_channel = dma_private->dma_channel; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Stop the DMA */ 7758c2ecf20Sopenharmony_ci out_be32(&dma_channel->mr, CCSR_DMA_MR_CA); 7768c2ecf20Sopenharmony_ci out_be32(&dma_channel->mr, 0); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* Reset all the other registers */ 7798c2ecf20Sopenharmony_ci out_be32(&dma_channel->sr, -1); 7808c2ecf20Sopenharmony_ci out_be32(&dma_channel->clndar, 0); 7818c2ecf20Sopenharmony_ci out_be32(&dma_channel->eclndar, 0); 7828c2ecf20Sopenharmony_ci out_be32(&dma_channel->satr, 0); 7838c2ecf20Sopenharmony_ci out_be32(&dma_channel->sar, 0); 7848c2ecf20Sopenharmony_ci out_be32(&dma_channel->datr, 0); 7858c2ecf20Sopenharmony_ci out_be32(&dma_channel->dar, 0); 7868c2ecf20Sopenharmony_ci out_be32(&dma_channel->bcr, 0); 7878c2ecf20Sopenharmony_ci out_be32(&dma_channel->nlndar, 0); 7888c2ecf20Sopenharmony_ci out_be32(&dma_channel->enlndar, 0); 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci return 0; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci/** 7958c2ecf20Sopenharmony_ci * fsl_dma_close: close the stream. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_cistatic int fsl_dma_close(struct snd_soc_component *component, 7988c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 8018c2ecf20Sopenharmony_ci struct fsl_dma_private *dma_private = runtime->private_data; 8028c2ecf20Sopenharmony_ci struct device *dev = component->dev; 8038c2ecf20Sopenharmony_ci struct dma_object *dma = 8048c2ecf20Sopenharmony_ci container_of(component->driver, struct dma_object, dai); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (dma_private) { 8078c2ecf20Sopenharmony_ci if (dma_private->irq) 8088c2ecf20Sopenharmony_ci free_irq(dma_private->irq, dma_private); 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* Deallocate the fsl_dma_private structure */ 8118c2ecf20Sopenharmony_ci dma_free_coherent(dev, sizeof(struct fsl_dma_private), 8128c2ecf20Sopenharmony_ci dma_private, dma_private->ld_buf_phys); 8138c2ecf20Sopenharmony_ci substream->runtime->private_data = NULL; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci dma->assigned = false; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci return 0; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci/* 8228c2ecf20Sopenharmony_ci * Remove this PCM driver. 8238c2ecf20Sopenharmony_ci */ 8248c2ecf20Sopenharmony_cistatic void fsl_dma_free_dma_buffers(struct snd_soc_component *component, 8258c2ecf20Sopenharmony_ci struct snd_pcm *pcm) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 8288c2ecf20Sopenharmony_ci unsigned int i; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) { 8318c2ecf20Sopenharmony_ci substream = pcm->streams[i].substream; 8328c2ecf20Sopenharmony_ci if (substream) { 8338c2ecf20Sopenharmony_ci snd_dma_free_pages(&substream->dma_buffer); 8348c2ecf20Sopenharmony_ci substream->dma_buffer.area = NULL; 8358c2ecf20Sopenharmony_ci substream->dma_buffer.addr = 0; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci/** 8418c2ecf20Sopenharmony_ci * find_ssi_node -- returns the SSI node that points to its DMA channel node 8428c2ecf20Sopenharmony_ci * 8438c2ecf20Sopenharmony_ci * Although this DMA driver attempts to operate independently of the other 8448c2ecf20Sopenharmony_ci * devices, it still needs to determine some information about the SSI device 8458c2ecf20Sopenharmony_ci * that it's working with. Unfortunately, the device tree does not contain 8468c2ecf20Sopenharmony_ci * a pointer from the DMA channel node to the SSI node -- the pointer goes the 8478c2ecf20Sopenharmony_ci * other way. So we need to scan the device tree for SSI nodes until we find 8488c2ecf20Sopenharmony_ci * the one that points to the given DMA channel node. It's ugly, but at least 8498c2ecf20Sopenharmony_ci * it's contained in this one function. 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_cistatic struct device_node *find_ssi_node(struct device_node *dma_channel_np) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci struct device_node *ssi_np, *np; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci for_each_compatible_node(ssi_np, NULL, "fsl,mpc8610-ssi") { 8568c2ecf20Sopenharmony_ci /* Check each DMA phandle to see if it points to us. We 8578c2ecf20Sopenharmony_ci * assume that device_node pointers are a valid comparison. 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_ci np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0); 8608c2ecf20Sopenharmony_ci of_node_put(np); 8618c2ecf20Sopenharmony_ci if (np == dma_channel_np) 8628c2ecf20Sopenharmony_ci return ssi_np; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0); 8658c2ecf20Sopenharmony_ci of_node_put(np); 8668c2ecf20Sopenharmony_ci if (np == dma_channel_np) 8678c2ecf20Sopenharmony_ci return ssi_np; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci return NULL; 8718c2ecf20Sopenharmony_ci} 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_cistatic int fsl_soc_dma_probe(struct platform_device *pdev) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct dma_object *dma; 8768c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 8778c2ecf20Sopenharmony_ci struct device_node *ssi_np; 8788c2ecf20Sopenharmony_ci struct resource res; 8798c2ecf20Sopenharmony_ci const uint32_t *iprop; 8808c2ecf20Sopenharmony_ci int ret; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* Find the SSI node that points to us. */ 8838c2ecf20Sopenharmony_ci ssi_np = find_ssi_node(np); 8848c2ecf20Sopenharmony_ci if (!ssi_np) { 8858c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "cannot find parent SSI node\n"); 8868c2ecf20Sopenharmony_ci return -ENODEV; 8878c2ecf20Sopenharmony_ci } 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci ret = of_address_to_resource(ssi_np, 0, &res); 8908c2ecf20Sopenharmony_ci if (ret) { 8918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not determine resources for %pOF\n", 8928c2ecf20Sopenharmony_ci ssi_np); 8938c2ecf20Sopenharmony_ci of_node_put(ssi_np); 8948c2ecf20Sopenharmony_ci return ret; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci dma = kzalloc(sizeof(*dma), GFP_KERNEL); 8988c2ecf20Sopenharmony_ci if (!dma) { 8998c2ecf20Sopenharmony_ci of_node_put(ssi_np); 9008c2ecf20Sopenharmony_ci return -ENOMEM; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci dma->dai.name = DRV_NAME; 9048c2ecf20Sopenharmony_ci dma->dai.open = fsl_dma_open; 9058c2ecf20Sopenharmony_ci dma->dai.close = fsl_dma_close; 9068c2ecf20Sopenharmony_ci dma->dai.hw_params = fsl_dma_hw_params; 9078c2ecf20Sopenharmony_ci dma->dai.hw_free = fsl_dma_hw_free; 9088c2ecf20Sopenharmony_ci dma->dai.pointer = fsl_dma_pointer; 9098c2ecf20Sopenharmony_ci dma->dai.pcm_construct = fsl_dma_new; 9108c2ecf20Sopenharmony_ci dma->dai.pcm_destruct = fsl_dma_free_dma_buffers; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Store the SSI-specific information that we need */ 9138c2ecf20Sopenharmony_ci dma->ssi_stx_phys = res.start + REG_SSI_STX0; 9148c2ecf20Sopenharmony_ci dma->ssi_srx_phys = res.start + REG_SSI_SRX0; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); 9178c2ecf20Sopenharmony_ci if (iprop) 9188c2ecf20Sopenharmony_ci dma->ssi_fifo_depth = be32_to_cpup(iprop); 9198c2ecf20Sopenharmony_ci else 9208c2ecf20Sopenharmony_ci /* Older 8610 DTs didn't have the fifo-depth property */ 9218c2ecf20Sopenharmony_ci dma->ssi_fifo_depth = 8; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci of_node_put(ssi_np); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0); 9268c2ecf20Sopenharmony_ci if (ret) { 9278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not register platform\n"); 9288c2ecf20Sopenharmony_ci kfree(dma); 9298c2ecf20Sopenharmony_ci return ret; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci dma->channel = of_iomap(np, 0); 9338c2ecf20Sopenharmony_ci dma->irq = irq_of_parse_and_map(np, 0); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, dma); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci return 0; 9388c2ecf20Sopenharmony_ci} 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic int fsl_soc_dma_remove(struct platform_device *pdev) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci struct dma_object *dma = dev_get_drvdata(&pdev->dev); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci iounmap(dma->channel); 9458c2ecf20Sopenharmony_ci irq_dispose_mapping(dma->irq); 9468c2ecf20Sopenharmony_ci kfree(dma); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci return 0; 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic const struct of_device_id fsl_soc_dma_ids[] = { 9528c2ecf20Sopenharmony_ci { .compatible = "fsl,ssi-dma-channel", }, 9538c2ecf20Sopenharmony_ci {} 9548c2ecf20Sopenharmony_ci}; 9558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, fsl_soc_dma_ids); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic struct platform_driver fsl_soc_dma_driver = { 9588c2ecf20Sopenharmony_ci .driver = { 9598c2ecf20Sopenharmony_ci .name = "fsl-pcm-audio", 9608c2ecf20Sopenharmony_ci .of_match_table = fsl_soc_dma_ids, 9618c2ecf20Sopenharmony_ci }, 9628c2ecf20Sopenharmony_ci .probe = fsl_soc_dma_probe, 9638c2ecf20Sopenharmony_ci .remove = fsl_soc_dma_remove, 9648c2ecf20Sopenharmony_ci}; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_cimodule_platform_driver(fsl_soc_dma_driver); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ciMODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 9698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Freescale Elo DMA ASoC PCM Driver"); 9708c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 971