18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * pxa2xx-i2s.c -- ALSA Soc Audio Layer 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2005 Wolfson Microelectronics PLC. 68c2ecf20Sopenharmony_ci * Author: Liam Girdwood 78c2ecf20Sopenharmony_ci * lrg@slimlogic.co.uk 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <sound/core.h> 188c2ecf20Sopenharmony_ci#include <sound/pcm.h> 198c2ecf20Sopenharmony_ci#include <sound/initval.h> 208c2ecf20Sopenharmony_ci#include <sound/soc.h> 218c2ecf20Sopenharmony_ci#include <sound/pxa2xx-lib.h> 228c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <mach/hardware.h> 258c2ecf20Sopenharmony_ci#include <mach/audio.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "pxa2xx-i2s.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * I2S Controller Register and Bit Definitions 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci#define SACR0 __REG(0x40400000) /* Global Control Register */ 338c2ecf20Sopenharmony_ci#define SACR1 __REG(0x40400004) /* Serial Audio I 2 S/MSB-Justified Control Register */ 348c2ecf20Sopenharmony_ci#define SASR0 __REG(0x4040000C) /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */ 358c2ecf20Sopenharmony_ci#define SAIMR __REG(0x40400014) /* Serial Audio Interrupt Mask Register */ 368c2ecf20Sopenharmony_ci#define SAICR __REG(0x40400018) /* Serial Audio Interrupt Clear Register */ 378c2ecf20Sopenharmony_ci#define SADIV __REG(0x40400060) /* Audio Clock Divider Register. */ 388c2ecf20Sopenharmony_ci#define SADR __REG(0x40400080) /* Serial Audio Data Register (TX and RX FIFO access Register). */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define SACR0_RFTH(x) ((x) << 12) /* Rx FIFO Interrupt or DMA Trigger Threshold */ 418c2ecf20Sopenharmony_ci#define SACR0_TFTH(x) ((x) << 8) /* Tx FIFO Interrupt or DMA Trigger Threshold */ 428c2ecf20Sopenharmony_ci#define SACR0_STRF (1 << 5) /* FIFO Select for EFWR Special Function */ 438c2ecf20Sopenharmony_ci#define SACR0_EFWR (1 << 4) /* Enable EFWR Function */ 448c2ecf20Sopenharmony_ci#define SACR0_RST (1 << 3) /* FIFO, i2s Register Reset */ 458c2ecf20Sopenharmony_ci#define SACR0_BCKD (1 << 2) /* Bit Clock Direction */ 468c2ecf20Sopenharmony_ci#define SACR0_ENB (1 << 0) /* Enable I2S Link */ 478c2ecf20Sopenharmony_ci#define SACR1_ENLBF (1 << 5) /* Enable Loopback */ 488c2ecf20Sopenharmony_ci#define SACR1_DRPL (1 << 4) /* Disable Replaying Function */ 498c2ecf20Sopenharmony_ci#define SACR1_DREC (1 << 3) /* Disable Recording Function */ 508c2ecf20Sopenharmony_ci#define SACR1_AMSL (1 << 0) /* Specify Alternate Mode */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define SASR0_I2SOFF (1 << 7) /* Controller Status */ 538c2ecf20Sopenharmony_ci#define SASR0_ROR (1 << 6) /* Rx FIFO Overrun */ 548c2ecf20Sopenharmony_ci#define SASR0_TUR (1 << 5) /* Tx FIFO Underrun */ 558c2ecf20Sopenharmony_ci#define SASR0_RFS (1 << 4) /* Rx FIFO Service Request */ 568c2ecf20Sopenharmony_ci#define SASR0_TFS (1 << 3) /* Tx FIFO Service Request */ 578c2ecf20Sopenharmony_ci#define SASR0_BSY (1 << 2) /* I2S Busy */ 588c2ecf20Sopenharmony_ci#define SASR0_RNE (1 << 1) /* Rx FIFO Not Empty */ 598c2ecf20Sopenharmony_ci#define SASR0_TNF (1 << 0) /* Tx FIFO Not Empty */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define SAICR_ROR (1 << 6) /* Clear Rx FIFO Overrun Interrupt */ 628c2ecf20Sopenharmony_ci#define SAICR_TUR (1 << 5) /* Clear Tx FIFO Underrun Interrupt */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define SAIMR_ROR (1 << 6) /* Enable Rx FIFO Overrun Condition Interrupt */ 658c2ecf20Sopenharmony_ci#define SAIMR_TUR (1 << 5) /* Enable Tx FIFO Underrun Condition Interrupt */ 668c2ecf20Sopenharmony_ci#define SAIMR_RFS (1 << 4) /* Enable Rx FIFO Service Interrupt */ 678c2ecf20Sopenharmony_ci#define SAIMR_TFS (1 << 3) /* Enable Tx FIFO Service Interrupt */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct pxa_i2s_port { 708c2ecf20Sopenharmony_ci u32 sadiv; 718c2ecf20Sopenharmony_ci u32 sacr0; 728c2ecf20Sopenharmony_ci u32 sacr1; 738c2ecf20Sopenharmony_ci u32 saimr; 748c2ecf20Sopenharmony_ci int master; 758c2ecf20Sopenharmony_ci u32 fmt; 768c2ecf20Sopenharmony_ci}; 778c2ecf20Sopenharmony_cistatic struct pxa_i2s_port pxa_i2s; 788c2ecf20Sopenharmony_cistatic struct clk *clk_i2s; 798c2ecf20Sopenharmony_cistatic int clk_ena = 0; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = { 828c2ecf20Sopenharmony_ci .addr = __PREG(SADR), 838c2ecf20Sopenharmony_ci .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 848c2ecf20Sopenharmony_ci .chan_name = "tx", 858c2ecf20Sopenharmony_ci .maxburst = 32, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = { 898c2ecf20Sopenharmony_ci .addr = __PREG(SADR), 908c2ecf20Sopenharmony_ci .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 918c2ecf20Sopenharmony_ci .chan_name = "rx", 928c2ecf20Sopenharmony_ci .maxburst = 32, 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int pxa2xx_i2s_startup(struct snd_pcm_substream *substream, 968c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 998c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (IS_ERR(clk_i2s)) 1028c2ecf20Sopenharmony_ci return PTR_ERR(clk_i2s); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (!snd_soc_dai_active(cpu_dai)) 1058c2ecf20Sopenharmony_ci SACR0 = 0; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return 0; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* wait for I2S controller to be ready */ 1118c2ecf20Sopenharmony_cistatic int pxa_i2s_wait(void) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci int i; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* flush the Rx FIFO */ 1168c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 1178c2ecf20Sopenharmony_ci SADR; 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, 1228c2ecf20Sopenharmony_ci unsigned int fmt) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci /* interface format */ 1258c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 1268c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 1278c2ecf20Sopenharmony_ci pxa_i2s.fmt = 0; 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 1308c2ecf20Sopenharmony_ci pxa_i2s.fmt = SACR1_AMSL; 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 1358c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 1368c2ecf20Sopenharmony_ci pxa_i2s.master = 1; 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFS: 1398c2ecf20Sopenharmony_ci pxa_i2s.master = 0; 1408c2ecf20Sopenharmony_ci break; 1418c2ecf20Sopenharmony_ci default: 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, 1488c2ecf20Sopenharmony_ci int clk_id, unsigned int freq, int dir) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci if (clk_id != PXA2XX_I2S_SYSCLK) 1518c2ecf20Sopenharmony_ci return -ENODEV; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, 1578c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 1588c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (WARN_ON(IS_ERR(clk_i2s))) 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci clk_prepare_enable(clk_i2s); 1658c2ecf20Sopenharmony_ci clk_ena = 1; 1668c2ecf20Sopenharmony_ci pxa_i2s_wait(); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1698c2ecf20Sopenharmony_ci dma_data = &pxa2xx_i2s_pcm_stereo_out; 1708c2ecf20Sopenharmony_ci else 1718c2ecf20Sopenharmony_ci dma_data = &pxa2xx_i2s_pcm_stereo_in; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci snd_soc_dai_set_dma_data(dai, substream, dma_data); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* is port used by another stream */ 1768c2ecf20Sopenharmony_ci if (!(SACR0 & SACR0_ENB)) { 1778c2ecf20Sopenharmony_ci SACR0 = 0; 1788c2ecf20Sopenharmony_ci if (pxa_i2s.master) 1798c2ecf20Sopenharmony_ci SACR0 |= SACR0_BCKD; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1); 1828c2ecf20Sopenharmony_ci SACR1 |= pxa_i2s.fmt; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1858c2ecf20Sopenharmony_ci SAIMR |= SAIMR_TFS; 1868c2ecf20Sopenharmony_ci else 1878c2ecf20Sopenharmony_ci SAIMR |= SAIMR_RFS; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci switch (params_rate(params)) { 1908c2ecf20Sopenharmony_ci case 8000: 1918c2ecf20Sopenharmony_ci SADIV = 0x48; 1928c2ecf20Sopenharmony_ci break; 1938c2ecf20Sopenharmony_ci case 11025: 1948c2ecf20Sopenharmony_ci SADIV = 0x34; 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci case 16000: 1978c2ecf20Sopenharmony_ci SADIV = 0x24; 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci case 22050: 2008c2ecf20Sopenharmony_ci SADIV = 0x1a; 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci case 44100: 2038c2ecf20Sopenharmony_ci SADIV = 0xd; 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci case 48000: 2068c2ecf20Sopenharmony_ci SADIV = 0xc; 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci case 96000: /* not in manual and possibly slightly inaccurate */ 2098c2ecf20Sopenharmony_ci SADIV = 0x6; 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 2178c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci int ret = 0; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci switch (cmd) { 2228c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2238c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2248c2ecf20Sopenharmony_ci SACR1 &= ~SACR1_DRPL; 2258c2ecf20Sopenharmony_ci else 2268c2ecf20Sopenharmony_ci SACR1 &= ~SACR1_DREC; 2278c2ecf20Sopenharmony_ci SACR0 |= SACR0_ENB; 2288c2ecf20Sopenharmony_ci break; 2298c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 2308c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 2318c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 2328c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 2338c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci default: 2368c2ecf20Sopenharmony_ci ret = -EINVAL; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return ret; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream, 2438c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 2468c2ecf20Sopenharmony_ci SACR1 |= SACR1_DRPL; 2478c2ecf20Sopenharmony_ci SAIMR &= ~SAIMR_TFS; 2488c2ecf20Sopenharmony_ci } else { 2498c2ecf20Sopenharmony_ci SACR1 |= SACR1_DREC; 2508c2ecf20Sopenharmony_ci SAIMR &= ~SAIMR_RFS; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) { 2548c2ecf20Sopenharmony_ci SACR0 &= ~SACR0_ENB; 2558c2ecf20Sopenharmony_ci pxa_i2s_wait(); 2568c2ecf20Sopenharmony_ci if (clk_ena) { 2578c2ecf20Sopenharmony_ci clk_disable_unprepare(clk_i2s); 2588c2ecf20Sopenharmony_ci clk_ena = 0; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 2648c2ecf20Sopenharmony_cistatic int pxa2xx_soc_pcm_suspend(struct snd_soc_component *component) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci /* store registers */ 2678c2ecf20Sopenharmony_ci pxa_i2s.sacr0 = SACR0; 2688c2ecf20Sopenharmony_ci pxa_i2s.sacr1 = SACR1; 2698c2ecf20Sopenharmony_ci pxa_i2s.saimr = SAIMR; 2708c2ecf20Sopenharmony_ci pxa_i2s.sadiv = SADIV; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* deactivate link */ 2738c2ecf20Sopenharmony_ci SACR0 &= ~SACR0_ENB; 2748c2ecf20Sopenharmony_ci pxa_i2s_wait(); 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int pxa2xx_soc_pcm_resume(struct snd_soc_component *component) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci pxa_i2s_wait(); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB; 2838c2ecf20Sopenharmony_ci SACR1 = pxa_i2s.sacr1; 2848c2ecf20Sopenharmony_ci SAIMR = pxa_i2s.saimr; 2858c2ecf20Sopenharmony_ci SADIV = pxa_i2s.sadiv; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci SACR0 = pxa_i2s.sacr0; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci#else 2938c2ecf20Sopenharmony_ci#define pxa2xx_soc_pcm_suspend NULL 2948c2ecf20Sopenharmony_ci#define pxa2xx_soc_pcm_resume NULL 2958c2ecf20Sopenharmony_ci#endif 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int pxa2xx_i2s_probe(struct snd_soc_dai *dai) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci clk_i2s = clk_get(dai->dev, "I2SCLK"); 3008c2ecf20Sopenharmony_ci if (IS_ERR(clk_i2s)) 3018c2ecf20Sopenharmony_ci return PTR_ERR(clk_i2s); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * PXA Developer's Manual: 3058c2ecf20Sopenharmony_ci * If SACR0[ENB] is toggled in the middle of a normal operation, 3068c2ecf20Sopenharmony_ci * the SACR0[RST] bit must also be set and cleared to reset all 3078c2ecf20Sopenharmony_ci * I2S controller registers. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci SACR0 = SACR0_RST; 3108c2ecf20Sopenharmony_ci SACR0 = 0; 3118c2ecf20Sopenharmony_ci /* Make sure RPL and REC are disabled */ 3128c2ecf20Sopenharmony_ci SACR1 = SACR1_DRPL | SACR1_DREC; 3138c2ecf20Sopenharmony_ci /* Along with FIFO servicing */ 3148c2ecf20Sopenharmony_ci SAIMR &= ~(SAIMR_RFS | SAIMR_TFS); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, &pxa2xx_i2s_pcm_stereo_out, 3178c2ecf20Sopenharmony_ci &pxa2xx_i2s_pcm_stereo_in); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int pxa2xx_i2s_remove(struct snd_soc_dai *dai) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci clk_put(clk_i2s); 3258c2ecf20Sopenharmony_ci clk_i2s = ERR_PTR(-ENOENT); 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ 3308c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ 3318c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops pxa_i2s_dai_ops = { 3348c2ecf20Sopenharmony_ci .startup = pxa2xx_i2s_startup, 3358c2ecf20Sopenharmony_ci .shutdown = pxa2xx_i2s_shutdown, 3368c2ecf20Sopenharmony_ci .trigger = pxa2xx_i2s_trigger, 3378c2ecf20Sopenharmony_ci .hw_params = pxa2xx_i2s_hw_params, 3388c2ecf20Sopenharmony_ci .set_fmt = pxa2xx_i2s_set_dai_fmt, 3398c2ecf20Sopenharmony_ci .set_sysclk = pxa2xx_i2s_set_dai_sysclk, 3408c2ecf20Sopenharmony_ci}; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver pxa_i2s_dai = { 3438c2ecf20Sopenharmony_ci .probe = pxa2xx_i2s_probe, 3448c2ecf20Sopenharmony_ci .remove = pxa2xx_i2s_remove, 3458c2ecf20Sopenharmony_ci .playback = { 3468c2ecf20Sopenharmony_ci .channels_min = 2, 3478c2ecf20Sopenharmony_ci .channels_max = 2, 3488c2ecf20Sopenharmony_ci .rates = PXA2XX_I2S_RATES, 3498c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 3508c2ecf20Sopenharmony_ci .capture = { 3518c2ecf20Sopenharmony_ci .channels_min = 2, 3528c2ecf20Sopenharmony_ci .channels_max = 2, 3538c2ecf20Sopenharmony_ci .rates = PXA2XX_I2S_RATES, 3548c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 3558c2ecf20Sopenharmony_ci .ops = &pxa_i2s_dai_ops, 3568c2ecf20Sopenharmony_ci .symmetric_rates = 1, 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver pxa_i2s_component = { 3608c2ecf20Sopenharmony_ci .name = "pxa-i2s", 3618c2ecf20Sopenharmony_ci .pcm_construct = pxa2xx_soc_pcm_new, 3628c2ecf20Sopenharmony_ci .pcm_destruct = pxa2xx_soc_pcm_free, 3638c2ecf20Sopenharmony_ci .open = pxa2xx_soc_pcm_open, 3648c2ecf20Sopenharmony_ci .close = pxa2xx_soc_pcm_close, 3658c2ecf20Sopenharmony_ci .hw_params = pxa2xx_soc_pcm_hw_params, 3668c2ecf20Sopenharmony_ci .hw_free = pxa2xx_soc_pcm_hw_free, 3678c2ecf20Sopenharmony_ci .prepare = pxa2xx_soc_pcm_prepare, 3688c2ecf20Sopenharmony_ci .trigger = pxa2xx_soc_pcm_trigger, 3698c2ecf20Sopenharmony_ci .pointer = pxa2xx_soc_pcm_pointer, 3708c2ecf20Sopenharmony_ci .mmap = pxa2xx_soc_pcm_mmap, 3718c2ecf20Sopenharmony_ci .suspend = pxa2xx_soc_pcm_suspend, 3728c2ecf20Sopenharmony_ci .resume = pxa2xx_soc_pcm_resume, 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int pxa2xx_i2s_drv_probe(struct platform_device *pdev) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(&pdev->dev, &pxa_i2s_component, 3788c2ecf20Sopenharmony_ci &pxa_i2s_dai, 1); 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic struct platform_driver pxa2xx_i2s_driver = { 3828c2ecf20Sopenharmony_ci .probe = pxa2xx_i2s_drv_probe, 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci .driver = { 3858c2ecf20Sopenharmony_ci .name = "pxa2xx-i2s", 3868c2ecf20Sopenharmony_ci }, 3878c2ecf20Sopenharmony_ci}; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic int __init pxa2xx_i2s_init(void) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci clk_i2s = ERR_PTR(-ENOENT); 3928c2ecf20Sopenharmony_ci return platform_driver_register(&pxa2xx_i2s_driver); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic void __exit pxa2xx_i2s_exit(void) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci platform_driver_unregister(&pxa2xx_i2s_driver); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cimodule_init(pxa2xx_i2s_init); 4018c2ecf20Sopenharmony_cimodule_exit(pxa2xx_i2s_exit); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci/* Module information */ 4048c2ecf20Sopenharmony_ciMODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk"); 4058c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("pxa2xx I2S SoC Interface"); 4068c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4078c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:pxa2xx-i2s"); 408