18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * omap-mcpdm.c -- OMAP ALSA SoC DAI driver using McPDM port 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2009 - 2011 Texas Instruments 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Misael Lopez Cruz <misael.lopez@ti.com> 88c2ecf20Sopenharmony_ci * Contact: Jorge Eduardo Candelaria <x0107209@ti.com> 98c2ecf20Sopenharmony_ci * Margarita Olaya <magi.olaya@ti.com> 108c2ecf20Sopenharmony_ci * Peter Ujfalusi <peter.ujfalusi@ti.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/err.h> 188c2ecf20Sopenharmony_ci#include <linux/io.h> 198c2ecf20Sopenharmony_ci#include <linux/irq.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 228c2ecf20Sopenharmony_ci#include <linux/of_device.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <sound/core.h> 258c2ecf20Sopenharmony_ci#include <sound/pcm.h> 268c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 278c2ecf20Sopenharmony_ci#include <sound/soc.h> 288c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include "omap-mcpdm.h" 318c2ecf20Sopenharmony_ci#include "sdma-pcm.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct mcpdm_link_config { 348c2ecf20Sopenharmony_ci u32 link_mask; /* channel mask for the direction */ 358c2ecf20Sopenharmony_ci u32 threshold; /* FIFO threshold */ 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct omap_mcpdm { 398c2ecf20Sopenharmony_ci struct device *dev; 408c2ecf20Sopenharmony_ci unsigned long phys_base; 418c2ecf20Sopenharmony_ci void __iomem *io_base; 428c2ecf20Sopenharmony_ci int irq; 438c2ecf20Sopenharmony_ci struct pm_qos_request pm_qos_req; 448c2ecf20Sopenharmony_ci int latency[2]; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci struct mutex mutex; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* Playback/Capture configuration */ 498c2ecf20Sopenharmony_ci struct mcpdm_link_config config[2]; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* McPDM dn offsets for rx1, and 2 channels */ 528c2ecf20Sopenharmony_ci u32 dn_rx_offset; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci /* McPDM needs to be restarted due to runtime reconfiguration */ 558c2ecf20Sopenharmony_ci bool restart; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* pm state for suspend/resume handling */ 588c2ecf20Sopenharmony_ci int pm_active_count; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_data[2]; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * Stream DMA parameters 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci writel_relaxed(val, mcpdm->io_base + reg); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic inline int omap_mcpdm_read(struct omap_mcpdm *mcpdm, u16 reg) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci return readl_relaxed(mcpdm->io_base + reg); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#ifdef DEBUG 788c2ecf20Sopenharmony_cistatic void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "***********************\n"); 818c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "IRQSTATUS_RAW: 0x%04x\n", 828c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS_RAW)); 838c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "IRQSTATUS: 0x%04x\n", 848c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS)); 858c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "IRQENABLE_SET: 0x%04x\n", 868c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_SET)); 878c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "IRQENABLE_CLR: 0x%04x\n", 888c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_IRQENABLE_CLR)); 898c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "IRQWAKE_EN: 0x%04x\n", 908c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_IRQWAKE_EN)); 918c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "DMAENABLE_SET: 0x%04x\n", 928c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_SET)); 938c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "DMAENABLE_CLR: 0x%04x\n", 948c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_DMAENABLE_CLR)); 958c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "DMAWAKEEN: 0x%04x\n", 968c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_DMAWAKEEN)); 978c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "CTRL: 0x%04x\n", 988c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL)); 998c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "DN_DATA: 0x%04x\n", 1008c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_DN_DATA)); 1018c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "UP_DATA: 0x%04x\n", 1028c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_UP_DATA)); 1038c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "FIFO_CTRL_DN: 0x%04x\n", 1048c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_DN)); 1058c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "FIFO_CTRL_UP: 0x%04x\n", 1068c2ecf20Sopenharmony_ci omap_mcpdm_read(mcpdm, MCPDM_REG_FIFO_CTRL_UP)); 1078c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "***********************\n"); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci#else 1108c2ecf20Sopenharmony_cistatic void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {} 1118c2ecf20Sopenharmony_ci#endif 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* 1148c2ecf20Sopenharmony_ci * Enables the transfer through the PDM interface to/from the Phoenix 1158c2ecf20Sopenharmony_ci * codec by enabling the corresponding UP or DN channels. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_cistatic void omap_mcpdm_start(struct omap_mcpdm *mcpdm) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 1208c2ecf20Sopenharmony_ci u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 1238c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ctrl |= link_mask; 1268c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 1298c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* 1338c2ecf20Sopenharmony_ci * Disables the transfer through the PDM interface to/from the Phoenix 1348c2ecf20Sopenharmony_ci * codec by disabling the corresponding UP or DN channels. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_cistatic void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 1398c2ecf20Sopenharmony_ci u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 1428c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ctrl &= ~(link_mask); 1458c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 1488c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * Is the physical McPDM interface active. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_cistatic inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL) & 1588c2ecf20Sopenharmony_ci (MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* 1628c2ecf20Sopenharmony_ci * Configures McPDM uplink, and downlink for audio. 1638c2ecf20Sopenharmony_ci * This function should be called before omap_mcpdm_start. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_cistatic void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET, 1728c2ecf20Sopenharmony_ci MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL | 1738c2ecf20Sopenharmony_ci MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Enable DN RX1/2 offset cancellation feature, if configured */ 1768c2ecf20Sopenharmony_ci if (mcpdm->dn_rx_offset) { 1778c2ecf20Sopenharmony_ci u32 dn_offset = mcpdm->dn_rx_offset; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); 1808c2ecf20Sopenharmony_ci dn_offset |= (MCPDM_DN_OFST_RX1_EN | MCPDM_DN_OFST_RX2_EN); 1818c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, 1858c2ecf20Sopenharmony_ci mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold); 1868c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, 1878c2ecf20Sopenharmony_ci mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET, 1908c2ecf20Sopenharmony_ci MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* 1948c2ecf20Sopenharmony_ci * Cleans McPDM uplink, and downlink configuration. 1958c2ecf20Sopenharmony_ci * This function should be called when the stream is closed. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic void omap_mcpdm_close_streams(struct omap_mcpdm *mcpdm) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci /* Disable irq request generation for downlink */ 2008c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR, 2018c2ecf20Sopenharmony_ci MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Disable DMA request generation for downlink */ 2048c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_DN_ENABLE); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* Disable irq request generation for uplink */ 2078c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_CLR, 2088c2ecf20Sopenharmony_ci MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Disable DMA request generation for uplink */ 2118c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_CLR, MCPDM_DMA_UP_ENABLE); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Disable RX1/2 offset cancellation */ 2148c2ecf20Sopenharmony_ci if (mcpdm->dn_rx_offset) 2158c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, 0); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic irqreturn_t omap_mcpdm_irq_handler(int irq, void *dev_id) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = dev_id; 2218c2ecf20Sopenharmony_ci int irq_status; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci irq_status = omap_mcpdm_read(mcpdm, MCPDM_REG_IRQSTATUS); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* Acknowledge irq event */ 2268c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_IRQSTATUS, irq_status); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (irq_status & MCPDM_DN_IRQ_FULL) 2298c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "DN (playback) FIFO Full\n"); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (irq_status & MCPDM_DN_IRQ_EMPTY) 2328c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "DN (playback) FIFO Empty\n"); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (irq_status & MCPDM_DN_IRQ) 2358c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "DN (playback) write request\n"); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (irq_status & MCPDM_UP_IRQ_FULL) 2388c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "UP (capture) FIFO Full\n"); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (irq_status & MCPDM_UP_IRQ_EMPTY) 2418c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "UP (capture) FIFO Empty\n"); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (irq_status & MCPDM_UP_IRQ) 2448c2ecf20Sopenharmony_ci dev_dbg(mcpdm->dev, "UP (capture) write request\n"); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, 2508c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci mutex_lock(&mcpdm->mutex); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!snd_soc_dai_active(dai)) 2578c2ecf20Sopenharmony_ci omap_mcpdm_open_streams(mcpdm); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci mutex_unlock(&mcpdm->mutex); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream, 2658c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 2688c2ecf20Sopenharmony_ci int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 2698c2ecf20Sopenharmony_ci int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; 2708c2ecf20Sopenharmony_ci int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci mutex_lock(&mcpdm->mutex); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (!snd_soc_dai_active(dai)) { 2758c2ecf20Sopenharmony_ci if (omap_mcpdm_active(mcpdm)) { 2768c2ecf20Sopenharmony_ci omap_mcpdm_stop(mcpdm); 2778c2ecf20Sopenharmony_ci omap_mcpdm_close_streams(mcpdm); 2788c2ecf20Sopenharmony_ci mcpdm->config[0].link_mask = 0; 2798c2ecf20Sopenharmony_ci mcpdm->config[1].link_mask = 0; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (mcpdm->latency[stream2]) 2848c2ecf20Sopenharmony_ci cpu_latency_qos_update_request(&mcpdm->pm_qos_req, 2858c2ecf20Sopenharmony_ci mcpdm->latency[stream2]); 2868c2ecf20Sopenharmony_ci else if (mcpdm->latency[stream1]) 2878c2ecf20Sopenharmony_ci cpu_latency_qos_remove_request(&mcpdm->pm_qos_req); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci mcpdm->latency[stream1] = 0; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci mutex_unlock(&mcpdm->mutex); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream, 2958c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 2968c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 2998c2ecf20Sopenharmony_ci int stream = substream->stream; 3008c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data; 3018c2ecf20Sopenharmony_ci u32 threshold; 3028c2ecf20Sopenharmony_ci int channels, latency; 3038c2ecf20Sopenharmony_ci int link_mask = 0; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci channels = params_channels(params); 3068c2ecf20Sopenharmony_ci switch (channels) { 3078c2ecf20Sopenharmony_ci case 5: 3088c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_CAPTURE) 3098c2ecf20Sopenharmony_ci /* up to 3 channels for capture */ 3108c2ecf20Sopenharmony_ci return -EINVAL; 3118c2ecf20Sopenharmony_ci link_mask |= 1 << 4; 3128c2ecf20Sopenharmony_ci fallthrough; 3138c2ecf20Sopenharmony_ci case 4: 3148c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_CAPTURE) 3158c2ecf20Sopenharmony_ci /* up to 3 channels for capture */ 3168c2ecf20Sopenharmony_ci return -EINVAL; 3178c2ecf20Sopenharmony_ci link_mask |= 1 << 3; 3188c2ecf20Sopenharmony_ci fallthrough; 3198c2ecf20Sopenharmony_ci case 3: 3208c2ecf20Sopenharmony_ci link_mask |= 1 << 2; 3218c2ecf20Sopenharmony_ci fallthrough; 3228c2ecf20Sopenharmony_ci case 2: 3238c2ecf20Sopenharmony_ci link_mask |= 1 << 1; 3248c2ecf20Sopenharmony_ci fallthrough; 3258c2ecf20Sopenharmony_ci case 1: 3268c2ecf20Sopenharmony_ci link_mask |= 1 << 0; 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci default: 3298c2ecf20Sopenharmony_ci /* unsupported number of channels */ 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci dma_data = snd_soc_dai_get_dma_data(dai, substream); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci threshold = mcpdm->config[stream].threshold; 3368c2ecf20Sopenharmony_ci /* Configure McPDM channels, and DMA packet size */ 3378c2ecf20Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 3388c2ecf20Sopenharmony_ci link_mask <<= 3; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* If capture is not running assume a stereo stream to come */ 3418c2ecf20Sopenharmony_ci if (!mcpdm->config[!stream].link_mask) 3428c2ecf20Sopenharmony_ci mcpdm->config[!stream].link_mask = 0x3; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci dma_data->maxburst = 3458c2ecf20Sopenharmony_ci (MCPDM_DN_THRES_MAX - threshold) * channels; 3468c2ecf20Sopenharmony_ci latency = threshold; 3478c2ecf20Sopenharmony_ci } else { 3488c2ecf20Sopenharmony_ci /* If playback is not running assume a stereo stream to come */ 3498c2ecf20Sopenharmony_ci if (!mcpdm->config[!stream].link_mask) 3508c2ecf20Sopenharmony_ci mcpdm->config[!stream].link_mask = (0x3 << 3); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci dma_data->maxburst = threshold * channels; 3538c2ecf20Sopenharmony_ci latency = (MCPDM_DN_THRES_MAX - threshold); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* 3578c2ecf20Sopenharmony_ci * The DMA must act to a DMA request within latency time (usec) to avoid 3588c2ecf20Sopenharmony_ci * under/overflow 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci mcpdm->latency[stream] = latency * USEC_PER_SEC / params_rate(params); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (!mcpdm->latency[stream]) 3638c2ecf20Sopenharmony_ci mcpdm->latency[stream] = 10; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* Check if we need to restart McPDM with this stream */ 3668c2ecf20Sopenharmony_ci if (mcpdm->config[stream].link_mask && 3678c2ecf20Sopenharmony_ci mcpdm->config[stream].link_mask != link_mask) 3688c2ecf20Sopenharmony_ci mcpdm->restart = true; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci mcpdm->config[stream].link_mask = link_mask; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return 0; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int omap_mcpdm_prepare(struct snd_pcm_substream *substream, 3768c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 3798c2ecf20Sopenharmony_ci struct pm_qos_request *pm_qos_req = &mcpdm->pm_qos_req; 3808c2ecf20Sopenharmony_ci int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); 3818c2ecf20Sopenharmony_ci int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; 3828c2ecf20Sopenharmony_ci int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; 3838c2ecf20Sopenharmony_ci int latency = mcpdm->latency[stream2]; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Prevent omap hardware from hitting off between FIFO fills */ 3868c2ecf20Sopenharmony_ci if (!latency || mcpdm->latency[stream1] < latency) 3878c2ecf20Sopenharmony_ci latency = mcpdm->latency[stream1]; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (cpu_latency_qos_request_active(pm_qos_req)) 3908c2ecf20Sopenharmony_ci cpu_latency_qos_update_request(pm_qos_req, latency); 3918c2ecf20Sopenharmony_ci else if (latency) 3928c2ecf20Sopenharmony_ci cpu_latency_qos_add_request(pm_qos_req, latency); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!omap_mcpdm_active(mcpdm)) { 3958c2ecf20Sopenharmony_ci omap_mcpdm_start(mcpdm); 3968c2ecf20Sopenharmony_ci omap_mcpdm_reg_dump(mcpdm); 3978c2ecf20Sopenharmony_ci } else if (mcpdm->restart) { 3988c2ecf20Sopenharmony_ci omap_mcpdm_stop(mcpdm); 3998c2ecf20Sopenharmony_ci omap_mcpdm_start(mcpdm); 4008c2ecf20Sopenharmony_ci mcpdm->restart = false; 4018c2ecf20Sopenharmony_ci omap_mcpdm_reg_dump(mcpdm); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops omap_mcpdm_dai_ops = { 4088c2ecf20Sopenharmony_ci .startup = omap_mcpdm_dai_startup, 4098c2ecf20Sopenharmony_ci .shutdown = omap_mcpdm_dai_shutdown, 4108c2ecf20Sopenharmony_ci .hw_params = omap_mcpdm_dai_hw_params, 4118c2ecf20Sopenharmony_ci .prepare = omap_mcpdm_prepare, 4128c2ecf20Sopenharmony_ci}; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int omap_mcpdm_probe(struct snd_soc_dai *dai) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 4178c2ecf20Sopenharmony_ci int ret; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci pm_runtime_enable(mcpdm->dev); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Disable lines while request is ongoing */ 4228c2ecf20Sopenharmony_ci pm_runtime_get_sync(mcpdm->dev); 4238c2ecf20Sopenharmony_ci omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 0, "McPDM", 4268c2ecf20Sopenharmony_ci (void *)mcpdm); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci pm_runtime_put_sync(mcpdm->dev); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (ret) { 4318c2ecf20Sopenharmony_ci dev_err(mcpdm->dev, "Request for IRQ failed\n"); 4328c2ecf20Sopenharmony_ci pm_runtime_disable(mcpdm->dev); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Configure McPDM threshold values */ 4368c2ecf20Sopenharmony_ci mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2; 4378c2ecf20Sopenharmony_ci mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold = 4388c2ecf20Sopenharmony_ci MCPDM_UP_THRES_MAX - 3; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, 4418c2ecf20Sopenharmony_ci &mcpdm->dma_data[SNDRV_PCM_STREAM_PLAYBACK], 4428c2ecf20Sopenharmony_ci &mcpdm->dma_data[SNDRV_PCM_STREAM_CAPTURE]); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return ret; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int omap_mcpdm_remove(struct snd_soc_dai *dai) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci free_irq(mcpdm->irq, (void *)mcpdm); 4528c2ecf20Sopenharmony_ci pm_runtime_disable(mcpdm->dev); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (cpu_latency_qos_request_active(&mcpdm->pm_qos_req)) 4558c2ecf20Sopenharmony_ci cpu_latency_qos_remove_request(&mcpdm->pm_qos_req); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return 0; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4618c2ecf20Sopenharmony_cistatic int omap_mcpdm_suspend(struct snd_soc_component *component) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = snd_soc_component_get_drvdata(component); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (snd_soc_component_active(component)) { 4668c2ecf20Sopenharmony_ci omap_mcpdm_stop(mcpdm); 4678c2ecf20Sopenharmony_ci omap_mcpdm_close_streams(mcpdm); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci mcpdm->pm_active_count = 0; 4718c2ecf20Sopenharmony_ci while (pm_runtime_active(mcpdm->dev)) { 4728c2ecf20Sopenharmony_ci pm_runtime_put_sync(mcpdm->dev); 4738c2ecf20Sopenharmony_ci mcpdm->pm_active_count++; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return 0; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic int omap_mcpdm_resume(struct snd_soc_component *component) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = snd_soc_component_get_drvdata(component); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (mcpdm->pm_active_count) { 4848c2ecf20Sopenharmony_ci while (mcpdm->pm_active_count--) 4858c2ecf20Sopenharmony_ci pm_runtime_get_sync(mcpdm->dev); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (snd_soc_component_active(component)) { 4888c2ecf20Sopenharmony_ci omap_mcpdm_open_streams(mcpdm); 4898c2ecf20Sopenharmony_ci omap_mcpdm_start(mcpdm); 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci#else 4978c2ecf20Sopenharmony_ci#define omap_mcpdm_suspend NULL 4988c2ecf20Sopenharmony_ci#define omap_mcpdm_resume NULL 4998c2ecf20Sopenharmony_ci#endif 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci#define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) 5028c2ecf20Sopenharmony_ci#define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver omap_mcpdm_dai = { 5058c2ecf20Sopenharmony_ci .probe = omap_mcpdm_probe, 5068c2ecf20Sopenharmony_ci .remove = omap_mcpdm_remove, 5078c2ecf20Sopenharmony_ci .probe_order = SND_SOC_COMP_ORDER_LATE, 5088c2ecf20Sopenharmony_ci .remove_order = SND_SOC_COMP_ORDER_EARLY, 5098c2ecf20Sopenharmony_ci .playback = { 5108c2ecf20Sopenharmony_ci .channels_min = 1, 5118c2ecf20Sopenharmony_ci .channels_max = 5, 5128c2ecf20Sopenharmony_ci .rates = OMAP_MCPDM_RATES, 5138c2ecf20Sopenharmony_ci .formats = OMAP_MCPDM_FORMATS, 5148c2ecf20Sopenharmony_ci .sig_bits = 24, 5158c2ecf20Sopenharmony_ci }, 5168c2ecf20Sopenharmony_ci .capture = { 5178c2ecf20Sopenharmony_ci .channels_min = 1, 5188c2ecf20Sopenharmony_ci .channels_max = 3, 5198c2ecf20Sopenharmony_ci .rates = OMAP_MCPDM_RATES, 5208c2ecf20Sopenharmony_ci .formats = OMAP_MCPDM_FORMATS, 5218c2ecf20Sopenharmony_ci .sig_bits = 24, 5228c2ecf20Sopenharmony_ci }, 5238c2ecf20Sopenharmony_ci .ops = &omap_mcpdm_dai_ops, 5248c2ecf20Sopenharmony_ci}; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver omap_mcpdm_component = { 5278c2ecf20Sopenharmony_ci .name = "omap-mcpdm", 5288c2ecf20Sopenharmony_ci .suspend = omap_mcpdm_suspend, 5298c2ecf20Sopenharmony_ci .resume = omap_mcpdm_resume, 5308c2ecf20Sopenharmony_ci}; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_civoid omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd, 5338c2ecf20Sopenharmony_ci u8 rx1, u8 rx2) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci mcpdm->dn_rx_offset = MCPDM_DNOFST_RX1(rx1) | MCPDM_DNOFST_RX2(rx2); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(omap_mcpdm_configure_dn_offsets); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int asoc_mcpdm_probe(struct platform_device *pdev) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct omap_mcpdm *mcpdm; 5448c2ecf20Sopenharmony_ci struct resource *res; 5458c2ecf20Sopenharmony_ci int ret; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL); 5488c2ecf20Sopenharmony_ci if (!mcpdm) 5498c2ecf20Sopenharmony_ci return -ENOMEM; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, mcpdm); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci mutex_init(&mcpdm->mutex); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); 5568c2ecf20Sopenharmony_ci if (res == NULL) 5578c2ecf20Sopenharmony_ci return -ENOMEM; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA; 5608c2ecf20Sopenharmony_ci mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci mcpdm->dma_data[0].filter_data = "dn_link"; 5638c2ecf20Sopenharmony_ci mcpdm->dma_data[1].filter_data = "up_link"; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); 5668c2ecf20Sopenharmony_ci mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res); 5678c2ecf20Sopenharmony_ci if (IS_ERR(mcpdm->io_base)) 5688c2ecf20Sopenharmony_ci return PTR_ERR(mcpdm->io_base); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci mcpdm->irq = platform_get_irq(pdev, 0); 5718c2ecf20Sopenharmony_ci if (mcpdm->irq < 0) 5728c2ecf20Sopenharmony_ci return mcpdm->irq; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci mcpdm->dev = &pdev->dev; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 5778c2ecf20Sopenharmony_ci &omap_mcpdm_component, 5788c2ecf20Sopenharmony_ci &omap_mcpdm_dai, 1); 5798c2ecf20Sopenharmony_ci if (ret) 5808c2ecf20Sopenharmony_ci return ret; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci return sdma_pcm_platform_register(&pdev->dev, "dn_link", "up_link"); 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic const struct of_device_id omap_mcpdm_of_match[] = { 5868c2ecf20Sopenharmony_ci { .compatible = "ti,omap4-mcpdm", }, 5878c2ecf20Sopenharmony_ci { } 5888c2ecf20Sopenharmony_ci}; 5898c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_mcpdm_of_match); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic struct platform_driver asoc_mcpdm_driver = { 5928c2ecf20Sopenharmony_ci .driver = { 5938c2ecf20Sopenharmony_ci .name = "omap-mcpdm", 5948c2ecf20Sopenharmony_ci .of_match_table = omap_mcpdm_of_match, 5958c2ecf20Sopenharmony_ci }, 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci .probe = asoc_mcpdm_probe, 5988c2ecf20Sopenharmony_ci}; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cimodule_platform_driver(asoc_mcpdm_driver); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:omap-mcpdm"); 6038c2ecf20Sopenharmony_ciMODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>"); 6048c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("OMAP PDM SoC Interface"); 6058c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 606