18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Linaro 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Jun Nie <jun.nie@linaro.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/clk.h> 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <sound/pcm.h> 158c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 168c2ecf20Sopenharmony_ci#include <sound/soc.h> 178c2ecf20Sopenharmony_ci#include <sound/soc-dai.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <sound/core.h> 208c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 218c2ecf20Sopenharmony_ci#include <sound/initval.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define ZX_I2S_PROCESS_CTRL 0x04 248c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_CTRL 0x08 258c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL 0x0C 268c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_STATUS 0x10 278c2ecf20Sopenharmony_ci#define ZX_I2S_INT_EN 0x14 288c2ecf20Sopenharmony_ci#define ZX_I2S_INT_STATUS 0x18 298c2ecf20Sopenharmony_ci#define ZX_I2S_DATA 0x1C 308c2ecf20Sopenharmony_ci#define ZX_I2S_FRAME_CNTR 0x20 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define I2S_DEAGULT_FIFO_THRES (0x10) 338c2ecf20Sopenharmony_ci#define I2S_MAX_FIFO_THRES (0x20) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define ZX_I2S_PROCESS_TX_EN (1 << 0) 368c2ecf20Sopenharmony_ci#define ZX_I2S_PROCESS_TX_DIS (0 << 0) 378c2ecf20Sopenharmony_ci#define ZX_I2S_PROCESS_RX_EN (1 << 1) 388c2ecf20Sopenharmony_ci#define ZX_I2S_PROCESS_RX_DIS (0 << 1) 398c2ecf20Sopenharmony_ci#define ZX_I2S_PROCESS_I2S_EN (1 << 2) 408c2ecf20Sopenharmony_ci#define ZX_I2S_PROCESS_I2S_DIS (0 << 2) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_MAST (1 << 0) 438c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_SLAVE (0 << 0) 448c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_MS_MASK (1 << 0) 458c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_LOOP (1 << 1) 468c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_NOR (0 << 1) 478c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_LOOP_MASK (1 << 1) 488c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_PTNR (1 << 2) 498c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_NTPR (0 << 2) 508c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_PHASE_MASK (1 << 2) 518c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_TDM (1 << 3) 528c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_I2S (0 << 3) 538c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_TIMING_MASK (1 << 3) 548c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_LONG_SYNC (1 << 4) 558c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_SHORT_SYNC (0 << 4) 568c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_SYNC_MASK (1 << 4) 578c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_TEAK_EN (1 << 5) 588c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_TEAK_DIS (0 << 5) 598c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_TEAK_MASK (1 << 5) 608c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_STD_I2S (0 << 6) 618c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_MSB_JUSTIF (1 << 6) 628c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_LSB_JUSTIF (2 << 6) 638c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_ALIGN_MASK (3 << 6) 648c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_CHN_MASK (7 << 8) 658c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_CHN(x) ((x - 1) << 8) 668c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_LANE_MASK (3 << 11) 678c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_LANE(x) ((x - 1) << 11) 688c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_TSCFG_MASK (7 << 13) 698c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_TSCFG(x) (x << 13) 708c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_TS_WIDTH_MASK (0x1f << 16) 718c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_TS_WIDTH(x) ((x - 1) << 16) 728c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_DATA_SIZE_MASK (0x1f << 21) 738c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_DATA_SIZE(x) ((x - 1) << 21) 748c2ecf20Sopenharmony_ci#define ZX_I2S_TIMING_CFG_ERR_MASK (1 << 31) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_TX_RST (1 << 0) 778c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_TX_RST_MASK (1 << 0) 788c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_RX_RST (1 << 1) 798c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_RX_RST_MASK (1 << 1) 808c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_TX_DMA_EN (1 << 4) 818c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_TX_DMA_DIS (0 << 4) 828c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_TX_DMA_MASK (1 << 4) 838c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_RX_DMA_EN (1 << 5) 848c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_RX_DMA_DIS (0 << 5) 858c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_RX_DMA_MASK (1 << 5) 868c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_TX_THRES_MASK (0x1F << 8) 878c2ecf20Sopenharmony_ci#define ZX_I2S_FIFO_CTRL_RX_THRES_MASK (0x1F << 16) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define CLK_RAT (32 * 4) 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistruct zx_i2s_info { 928c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_playback; 938c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_capture; 948c2ecf20Sopenharmony_ci struct clk *dai_wclk; 958c2ecf20Sopenharmony_ci struct clk *dai_pclk; 968c2ecf20Sopenharmony_ci void __iomem *reg_base; 978c2ecf20Sopenharmony_ci int master; 988c2ecf20Sopenharmony_ci resource_size_t mapbase; 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void zx_i2s_tx_en(void __iomem *base, bool on) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci unsigned long val; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); 1068c2ecf20Sopenharmony_ci if (on) 1078c2ecf20Sopenharmony_ci val |= ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN; 1088c2ecf20Sopenharmony_ci else 1098c2ecf20Sopenharmony_ci val &= ~(ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN); 1108c2ecf20Sopenharmony_ci writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void zx_i2s_rx_en(void __iomem *base, bool on) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci unsigned long val; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); 1188c2ecf20Sopenharmony_ci if (on) 1198c2ecf20Sopenharmony_ci val |= ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN; 1208c2ecf20Sopenharmony_ci else 1218c2ecf20Sopenharmony_ci val &= ~(ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN); 1228c2ecf20Sopenharmony_ci writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void zx_i2s_tx_dma_en(void __iomem *base, bool on) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci unsigned long val; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); 1308c2ecf20Sopenharmony_ci val |= ZX_I2S_FIFO_CTRL_TX_RST | (I2S_DEAGULT_FIFO_THRES << 8); 1318c2ecf20Sopenharmony_ci if (on) 1328c2ecf20Sopenharmony_ci val |= ZX_I2S_FIFO_CTRL_TX_DMA_EN; 1338c2ecf20Sopenharmony_ci else 1348c2ecf20Sopenharmony_ci val &= ~ZX_I2S_FIFO_CTRL_TX_DMA_EN; 1358c2ecf20Sopenharmony_ci writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void zx_i2s_rx_dma_en(void __iomem *base, bool on) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci unsigned long val; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); 1438c2ecf20Sopenharmony_ci val |= ZX_I2S_FIFO_CTRL_RX_RST | (I2S_DEAGULT_FIFO_THRES << 16); 1448c2ecf20Sopenharmony_ci if (on) 1458c2ecf20Sopenharmony_ci val |= ZX_I2S_FIFO_CTRL_RX_DMA_EN; 1468c2ecf20Sopenharmony_ci else 1478c2ecf20Sopenharmony_ci val &= ~ZX_I2S_FIFO_CTRL_RX_DMA_EN; 1488c2ecf20Sopenharmony_ci writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci#define ZX_I2S_RATES \ 1528c2ecf20Sopenharmony_ci (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ 1538c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 1548c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000| \ 1558c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define ZX_I2S_FMTBIT \ 1588c2ecf20Sopenharmony_ci (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ 1598c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE) 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int zx_i2s_dai_probe(struct snd_soc_dai *dai) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci snd_soc_dai_set_drvdata(dai, zx_i2s); 1668c2ecf20Sopenharmony_ci zx_i2s->dma_playback.addr = zx_i2s->mapbase + ZX_I2S_DATA; 1678c2ecf20Sopenharmony_ci zx_i2s->dma_playback.maxburst = 16; 1688c2ecf20Sopenharmony_ci zx_i2s->dma_capture.addr = zx_i2s->mapbase + ZX_I2S_DATA; 1698c2ecf20Sopenharmony_ci zx_i2s->dma_capture.maxburst = 16; 1708c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, &zx_i2s->dma_playback, 1718c2ecf20Sopenharmony_ci &zx_i2s->dma_capture); 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(cpu_dai); 1788c2ecf20Sopenharmony_ci unsigned long val; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); 1818c2ecf20Sopenharmony_ci val &= ~(ZX_I2S_TIMING_TIMING_MASK | ZX_I2S_TIMING_ALIGN_MASK | 1828c2ecf20Sopenharmony_ci ZX_I2S_TIMING_TEAK_MASK | ZX_I2S_TIMING_SYNC_MASK | 1838c2ecf20Sopenharmony_ci ZX_I2S_TIMING_MS_MASK); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 1868c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 1878c2ecf20Sopenharmony_ci val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_STD_I2S); 1888c2ecf20Sopenharmony_ci break; 1898c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 1908c2ecf20Sopenharmony_ci val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_MSB_JUSTIF); 1918c2ecf20Sopenharmony_ci break; 1928c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 1938c2ecf20Sopenharmony_ci val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_LSB_JUSTIF); 1948c2ecf20Sopenharmony_ci break; 1958c2ecf20Sopenharmony_ci default: 1968c2ecf20Sopenharmony_ci dev_err(cpu_dai->dev, "Unknown i2s timing\n"); 1978c2ecf20Sopenharmony_ci return -EINVAL; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 2018c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 2028c2ecf20Sopenharmony_ci /* Codec is master, and I2S is slave. */ 2038c2ecf20Sopenharmony_ci i2s->master = 0; 2048c2ecf20Sopenharmony_ci val |= ZX_I2S_TIMING_SLAVE; 2058c2ecf20Sopenharmony_ci break; 2068c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 2078c2ecf20Sopenharmony_ci /* Codec is slave, and I2S is master. */ 2088c2ecf20Sopenharmony_ci i2s->master = 1; 2098c2ecf20Sopenharmony_ci val |= ZX_I2S_TIMING_MAST; 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci default: 2128c2ecf20Sopenharmony_ci dev_err(cpu_dai->dev, "Unknown master/slave format\n"); 2138c2ecf20Sopenharmony_ci return -EINVAL; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int zx_i2s_hw_params(struct snd_pcm_substream *substream, 2218c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 2228c2ecf20Sopenharmony_ci struct snd_soc_dai *socdai) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(socdai); 2258c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data; 2268c2ecf20Sopenharmony_ci unsigned int lane, ch_num, len, ret = 0; 2278c2ecf20Sopenharmony_ci unsigned int ts_width = 32; 2288c2ecf20Sopenharmony_ci unsigned long val; 2298c2ecf20Sopenharmony_ci unsigned long chn_cfg; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci dma_data = snd_soc_dai_get_dma_data(socdai, substream); 2328c2ecf20Sopenharmony_ci dma_data->addr_width = ts_width >> 3; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); 2358c2ecf20Sopenharmony_ci val &= ~(ZX_I2S_TIMING_TS_WIDTH_MASK | ZX_I2S_TIMING_DATA_SIZE_MASK | 2368c2ecf20Sopenharmony_ci ZX_I2S_TIMING_LANE_MASK | ZX_I2S_TIMING_CHN_MASK | 2378c2ecf20Sopenharmony_ci ZX_I2S_TIMING_TSCFG_MASK); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci switch (params_format(params)) { 2408c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 2418c2ecf20Sopenharmony_ci len = 16; 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 2448c2ecf20Sopenharmony_ci len = 24; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 2478c2ecf20Sopenharmony_ci len = 32; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci default: 2508c2ecf20Sopenharmony_ci dev_err(socdai->dev, "Unknown data format\n"); 2518c2ecf20Sopenharmony_ci return -EINVAL; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci val |= ZX_I2S_TIMING_TS_WIDTH(ts_width) | ZX_I2S_TIMING_DATA_SIZE(len); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ch_num = params_channels(params); 2568c2ecf20Sopenharmony_ci switch (ch_num) { 2578c2ecf20Sopenharmony_ci case 1: 2588c2ecf20Sopenharmony_ci lane = 1; 2598c2ecf20Sopenharmony_ci chn_cfg = 2; 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci case 2: 2628c2ecf20Sopenharmony_ci case 4: 2638c2ecf20Sopenharmony_ci case 6: 2648c2ecf20Sopenharmony_ci case 8: 2658c2ecf20Sopenharmony_ci lane = ch_num / 2; 2668c2ecf20Sopenharmony_ci chn_cfg = 3; 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci default: 2698c2ecf20Sopenharmony_ci dev_err(socdai->dev, "Not support channel num %d\n", ch_num); 2708c2ecf20Sopenharmony_ci return -EINVAL; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci val |= ZX_I2S_TIMING_LANE(lane); 2738c2ecf20Sopenharmony_ci val |= ZX_I2S_TIMING_TSCFG(chn_cfg); 2748c2ecf20Sopenharmony_ci val |= ZX_I2S_TIMING_CHN(ch_num); 2758c2ecf20Sopenharmony_ci writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (i2s->master) 2788c2ecf20Sopenharmony_ci ret = clk_set_rate(i2s->dai_wclk, 2798c2ecf20Sopenharmony_ci params_rate(params) * ch_num * CLK_RAT); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int zx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 2858c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); 2888c2ecf20Sopenharmony_ci int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); 2898c2ecf20Sopenharmony_ci int ret = 0; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci switch (cmd) { 2928c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2938c2ecf20Sopenharmony_ci if (capture) 2948c2ecf20Sopenharmony_ci zx_i2s_rx_dma_en(zx_i2s->reg_base, true); 2958c2ecf20Sopenharmony_ci else 2968c2ecf20Sopenharmony_ci zx_i2s_tx_dma_en(zx_i2s->reg_base, true); 2978c2ecf20Sopenharmony_ci fallthrough; 2988c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 2998c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 3008c2ecf20Sopenharmony_ci if (capture) 3018c2ecf20Sopenharmony_ci zx_i2s_rx_en(zx_i2s->reg_base, true); 3028c2ecf20Sopenharmony_ci else 3038c2ecf20Sopenharmony_ci zx_i2s_tx_en(zx_i2s->reg_base, true); 3048c2ecf20Sopenharmony_ci break; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 3078c2ecf20Sopenharmony_ci if (capture) 3088c2ecf20Sopenharmony_ci zx_i2s_rx_dma_en(zx_i2s->reg_base, false); 3098c2ecf20Sopenharmony_ci else 3108c2ecf20Sopenharmony_ci zx_i2s_tx_dma_en(zx_i2s->reg_base, false); 3118c2ecf20Sopenharmony_ci fallthrough; 3128c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 3138c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 3148c2ecf20Sopenharmony_ci if (capture) 3158c2ecf20Sopenharmony_ci zx_i2s_rx_en(zx_i2s->reg_base, false); 3168c2ecf20Sopenharmony_ci else 3178c2ecf20Sopenharmony_ci zx_i2s_tx_en(zx_i2s->reg_base, false); 3188c2ecf20Sopenharmony_ci break; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci default: 3218c2ecf20Sopenharmony_ci ret = -EINVAL; 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return ret; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic int zx_i2s_startup(struct snd_pcm_substream *substream, 3298c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); 3328c2ecf20Sopenharmony_ci int ret; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ret = clk_prepare_enable(zx_i2s->dai_wclk); 3358c2ecf20Sopenharmony_ci if (ret) 3368c2ecf20Sopenharmony_ci return ret; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ret = clk_prepare_enable(zx_i2s->dai_pclk); 3398c2ecf20Sopenharmony_ci if (ret) { 3408c2ecf20Sopenharmony_ci clk_disable_unprepare(zx_i2s->dai_wclk); 3418c2ecf20Sopenharmony_ci return ret; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return ret; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic void zx_i2s_shutdown(struct snd_pcm_substream *substream, 3488c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci clk_disable_unprepare(zx_i2s->dai_wclk); 3538c2ecf20Sopenharmony_ci clk_disable_unprepare(zx_i2s->dai_pclk); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops zx_i2s_dai_ops = { 3578c2ecf20Sopenharmony_ci .trigger = zx_i2s_trigger, 3588c2ecf20Sopenharmony_ci .hw_params = zx_i2s_hw_params, 3598c2ecf20Sopenharmony_ci .set_fmt = zx_i2s_set_fmt, 3608c2ecf20Sopenharmony_ci .startup = zx_i2s_startup, 3618c2ecf20Sopenharmony_ci .shutdown = zx_i2s_shutdown, 3628c2ecf20Sopenharmony_ci}; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver zx_i2s_component = { 3658c2ecf20Sopenharmony_ci .name = "zx-i2s", 3668c2ecf20Sopenharmony_ci}; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver zx_i2s_dai = { 3698c2ecf20Sopenharmony_ci .name = "zx-i2s-dai", 3708c2ecf20Sopenharmony_ci .id = 0, 3718c2ecf20Sopenharmony_ci .probe = zx_i2s_dai_probe, 3728c2ecf20Sopenharmony_ci .playback = { 3738c2ecf20Sopenharmony_ci .channels_min = 1, 3748c2ecf20Sopenharmony_ci .channels_max = 8, 3758c2ecf20Sopenharmony_ci .rates = ZX_I2S_RATES, 3768c2ecf20Sopenharmony_ci .formats = ZX_I2S_FMTBIT, 3778c2ecf20Sopenharmony_ci }, 3788c2ecf20Sopenharmony_ci .capture = { 3798c2ecf20Sopenharmony_ci .channels_min = 1, 3808c2ecf20Sopenharmony_ci .channels_max = 2, 3818c2ecf20Sopenharmony_ci .rates = ZX_I2S_RATES, 3828c2ecf20Sopenharmony_ci .formats = ZX_I2S_FMTBIT, 3838c2ecf20Sopenharmony_ci }, 3848c2ecf20Sopenharmony_ci .ops = &zx_i2s_dai_ops, 3858c2ecf20Sopenharmony_ci}; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int zx_i2s_probe(struct platform_device *pdev) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct resource *res; 3908c2ecf20Sopenharmony_ci struct zx_i2s_info *zx_i2s; 3918c2ecf20Sopenharmony_ci int ret; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci zx_i2s = devm_kzalloc(&pdev->dev, sizeof(*zx_i2s), GFP_KERNEL); 3948c2ecf20Sopenharmony_ci if (!zx_i2s) 3958c2ecf20Sopenharmony_ci return -ENOMEM; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci zx_i2s->dai_wclk = devm_clk_get(&pdev->dev, "wclk"); 3988c2ecf20Sopenharmony_ci if (IS_ERR(zx_i2s->dai_wclk)) { 3998c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Fail to get wclk\n"); 4008c2ecf20Sopenharmony_ci return PTR_ERR(zx_i2s->dai_wclk); 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci zx_i2s->dai_pclk = devm_clk_get(&pdev->dev, "pclk"); 4048c2ecf20Sopenharmony_ci if (IS_ERR(zx_i2s->dai_pclk)) { 4058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Fail to get pclk\n"); 4068c2ecf20Sopenharmony_ci return PTR_ERR(zx_i2s->dai_pclk); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4108c2ecf20Sopenharmony_ci zx_i2s->mapbase = res->start; 4118c2ecf20Sopenharmony_ci zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res); 4128c2ecf20Sopenharmony_ci if (IS_ERR(zx_i2s->reg_base)) { 4138c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "ioremap failed!\n"); 4148c2ecf20Sopenharmony_ci return PTR_ERR(zx_i2s->reg_base); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL); 4188c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, zx_i2s); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &zx_i2s_component, 4218c2ecf20Sopenharmony_ci &zx_i2s_dai, 1); 4228c2ecf20Sopenharmony_ci if (ret) { 4238c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); 4248c2ecf20Sopenharmony_ci return ret; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 4288c2ecf20Sopenharmony_ci if (ret) 4298c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return ret; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic const struct of_device_id zx_i2s_dt_ids[] = { 4358c2ecf20Sopenharmony_ci { .compatible = "zte,zx296702-i2s", }, 4368c2ecf20Sopenharmony_ci {} 4378c2ecf20Sopenharmony_ci}; 4388c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, zx_i2s_dt_ids); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic struct platform_driver i2s_driver = { 4418c2ecf20Sopenharmony_ci .probe = zx_i2s_probe, 4428c2ecf20Sopenharmony_ci .driver = { 4438c2ecf20Sopenharmony_ci .name = "zx-i2s", 4448c2ecf20Sopenharmony_ci .of_match_table = zx_i2s_dt_ids, 4458c2ecf20Sopenharmony_ci }, 4468c2ecf20Sopenharmony_ci}; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cimodule_platform_driver(i2s_driver); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>"); 4518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ZTE I2S SoC DAI"); 4528c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 453