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/dmaengine.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/of_address.h> 168c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 178c2ecf20Sopenharmony_ci#include <sound/core.h> 188c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 198c2ecf20Sopenharmony_ci#include <sound/initval.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm.h> 218c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 228c2ecf20Sopenharmony_ci#include <sound/soc.h> 238c2ecf20Sopenharmony_ci#include <sound/soc-dai.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define ZX_CTRL 0x04 268c2ecf20Sopenharmony_ci#define ZX_FIFOCTRL 0x08 278c2ecf20Sopenharmony_ci#define ZX_INT_STATUS 0x10 288c2ecf20Sopenharmony_ci#define ZX_INT_MASK 0x14 298c2ecf20Sopenharmony_ci#define ZX_DATA 0x18 308c2ecf20Sopenharmony_ci#define ZX_VALID_BIT 0x1c 318c2ecf20Sopenharmony_ci#define ZX_CH_STA_1 0x20 328c2ecf20Sopenharmony_ci#define ZX_CH_STA_2 0x24 338c2ecf20Sopenharmony_ci#define ZX_CH_STA_3 0x28 348c2ecf20Sopenharmony_ci#define ZX_CH_STA_4 0x2c 358c2ecf20Sopenharmony_ci#define ZX_CH_STA_5 0x30 368c2ecf20Sopenharmony_ci#define ZX_CH_STA_6 0x34 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define ZX_CTRL_MODA_16 (0 << 6) 398c2ecf20Sopenharmony_ci#define ZX_CTRL_MODA_18 BIT(6) 408c2ecf20Sopenharmony_ci#define ZX_CTRL_MODA_20 (2 << 6) 418c2ecf20Sopenharmony_ci#define ZX_CTRL_MODA_24 (3 << 6) 428c2ecf20Sopenharmony_ci#define ZX_CTRL_MODA_MASK (3 << 6) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define ZX_CTRL_ENB BIT(4) 458c2ecf20Sopenharmony_ci#define ZX_CTRL_DNB (0 << 4) 468c2ecf20Sopenharmony_ci#define ZX_CTRL_ENB_MASK BIT(4) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define ZX_CTRL_TX_OPEN BIT(0) 498c2ecf20Sopenharmony_ci#define ZX_CTRL_TX_CLOSE (0 << 0) 508c2ecf20Sopenharmony_ci#define ZX_CTRL_TX_MASK BIT(0) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define ZX_CTRL_OPEN (ZX_CTRL_TX_OPEN | ZX_CTRL_ENB) 538c2ecf20Sopenharmony_ci#define ZX_CTRL_CLOSE (ZX_CTRL_TX_CLOSE | ZX_CTRL_DNB) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define ZX_CTRL_DOUBLE_TRACK (0 << 8) 568c2ecf20Sopenharmony_ci#define ZX_CTRL_LEFT_TRACK BIT(8) 578c2ecf20Sopenharmony_ci#define ZX_CTRL_RIGHT_TRACK (2 << 8) 588c2ecf20Sopenharmony_ci#define ZX_CTRL_TRACK_MASK (3 << 8) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define ZX_FIFOCTRL_TXTH_MASK (0x1f << 8) 618c2ecf20Sopenharmony_ci#define ZX_FIFOCTRL_TXTH(x) (x << 8) 628c2ecf20Sopenharmony_ci#define ZX_FIFOCTRL_TX_DMA_EN BIT(2) 638c2ecf20Sopenharmony_ci#define ZX_FIFOCTRL_TX_DMA_DIS (0 << 2) 648c2ecf20Sopenharmony_ci#define ZX_FIFOCTRL_TX_DMA_EN_MASK BIT(2) 658c2ecf20Sopenharmony_ci#define ZX_FIFOCTRL_TX_FIFO_RST BIT(0) 668c2ecf20Sopenharmony_ci#define ZX_FIFOCTRL_TX_FIFO_RST_MASK BIT(0) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define ZX_VALID_DOUBLE_TRACK (0 << 0) 698c2ecf20Sopenharmony_ci#define ZX_VALID_LEFT_TRACK BIT(1) 708c2ecf20Sopenharmony_ci#define ZX_VALID_RIGHT_TRACK (2 << 0) 718c2ecf20Sopenharmony_ci#define ZX_VALID_TRACK_MASK (3 << 0) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci#define ZX_SPDIF_CLK_RAT (2 * 32) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct zx_spdif_info { 768c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_data; 778c2ecf20Sopenharmony_ci struct clk *dai_clk; 788c2ecf20Sopenharmony_ci void __iomem *reg_base; 798c2ecf20Sopenharmony_ci resource_size_t mapbase; 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int zx_spdif_dai_probe(struct snd_soc_dai *dai) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci snd_soc_dai_set_drvdata(dai, zx_spdif); 878c2ecf20Sopenharmony_ci zx_spdif->dma_data.addr = zx_spdif->mapbase + ZX_DATA; 888c2ecf20Sopenharmony_ci zx_spdif->dma_data.maxburst = 8; 898c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, &zx_spdif->dma_data, NULL); 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic int zx_spdif_chanstats(void __iomem *base, unsigned int rate) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci u32 cstas1; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci switch (rate) { 988c2ecf20Sopenharmony_ci case 22050: 998c2ecf20Sopenharmony_ci cstas1 = IEC958_AES3_CON_FS_22050; 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci case 24000: 1028c2ecf20Sopenharmony_ci cstas1 = IEC958_AES3_CON_FS_24000; 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci case 32000: 1058c2ecf20Sopenharmony_ci cstas1 = IEC958_AES3_CON_FS_32000; 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci case 44100: 1088c2ecf20Sopenharmony_ci cstas1 = IEC958_AES3_CON_FS_44100; 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci case 48000: 1118c2ecf20Sopenharmony_ci cstas1 = IEC958_AES3_CON_FS_48000; 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci case 88200: 1148c2ecf20Sopenharmony_ci cstas1 = IEC958_AES3_CON_FS_88200; 1158c2ecf20Sopenharmony_ci break; 1168c2ecf20Sopenharmony_ci case 96000: 1178c2ecf20Sopenharmony_ci cstas1 = IEC958_AES3_CON_FS_96000; 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci case 176400: 1208c2ecf20Sopenharmony_ci cstas1 = IEC958_AES3_CON_FS_176400; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci case 192000: 1238c2ecf20Sopenharmony_ci cstas1 = IEC958_AES3_CON_FS_192000; 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci default: 1268c2ecf20Sopenharmony_ci return -EINVAL; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci cstas1 = cstas1 << 24; 1298c2ecf20Sopenharmony_ci cstas1 |= IEC958_AES0_CON_NOT_COPYRIGHT; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci writel_relaxed(cstas1, base + ZX_CH_STA_1); 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int zx_spdif_hw_params(struct snd_pcm_substream *substream, 1368c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 1378c2ecf20Sopenharmony_ci struct snd_soc_dai *socdai) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct zx_spdif_info *zx_spdif = dev_get_drvdata(socdai->dev); 1408c2ecf20Sopenharmony_ci struct zx_spdif_info *spdif = snd_soc_dai_get_drvdata(socdai); 1418c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data = 1428c2ecf20Sopenharmony_ci snd_soc_dai_get_dma_data(socdai, substream); 1438c2ecf20Sopenharmony_ci u32 val, ch_num, rate; 1448c2ecf20Sopenharmony_ci int ret; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci dma_data->addr_width = params_width(params) >> 3; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci val = readl_relaxed(zx_spdif->reg_base + ZX_CTRL); 1498c2ecf20Sopenharmony_ci val &= ~ZX_CTRL_MODA_MASK; 1508c2ecf20Sopenharmony_ci switch (params_format(params)) { 1518c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 1528c2ecf20Sopenharmony_ci val |= ZX_CTRL_MODA_16; 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S18_3LE: 1568c2ecf20Sopenharmony_ci val |= ZX_CTRL_MODA_18; 1578c2ecf20Sopenharmony_ci break; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S20_3LE: 1608c2ecf20Sopenharmony_ci val |= ZX_CTRL_MODA_20; 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 1648c2ecf20Sopenharmony_ci val |= ZX_CTRL_MODA_24; 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci default: 1678c2ecf20Sopenharmony_ci dev_err(socdai->dev, "Format not support!\n"); 1688c2ecf20Sopenharmony_ci return -EINVAL; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci ch_num = params_channels(params); 1728c2ecf20Sopenharmony_ci if (ch_num == 2) 1738c2ecf20Sopenharmony_ci val |= ZX_CTRL_DOUBLE_TRACK; 1748c2ecf20Sopenharmony_ci else 1758c2ecf20Sopenharmony_ci val |= ZX_CTRL_LEFT_TRACK; 1768c2ecf20Sopenharmony_ci writel_relaxed(val, zx_spdif->reg_base + ZX_CTRL); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci val = readl_relaxed(zx_spdif->reg_base + ZX_VALID_BIT); 1798c2ecf20Sopenharmony_ci val &= ~ZX_VALID_TRACK_MASK; 1808c2ecf20Sopenharmony_ci if (ch_num == 2) 1818c2ecf20Sopenharmony_ci val |= ZX_VALID_DOUBLE_TRACK; 1828c2ecf20Sopenharmony_ci else 1838c2ecf20Sopenharmony_ci val |= ZX_VALID_RIGHT_TRACK; 1848c2ecf20Sopenharmony_ci writel_relaxed(val, zx_spdif->reg_base + ZX_VALID_BIT); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci rate = params_rate(params); 1878c2ecf20Sopenharmony_ci ret = zx_spdif_chanstats(zx_spdif->reg_base, rate); 1888c2ecf20Sopenharmony_ci if (ret) 1898c2ecf20Sopenharmony_ci return ret; 1908c2ecf20Sopenharmony_ci return clk_set_rate(spdif->dai_clk, rate * ch_num * ZX_SPDIF_CLK_RAT); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic void zx_spdif_cfg_tx(void __iomem *base, int on) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci u32 val; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci val = readl_relaxed(base + ZX_CTRL); 1988c2ecf20Sopenharmony_ci val &= ~(ZX_CTRL_ENB_MASK | ZX_CTRL_TX_MASK); 1998c2ecf20Sopenharmony_ci val |= on ? ZX_CTRL_OPEN : ZX_CTRL_CLOSE; 2008c2ecf20Sopenharmony_ci writel_relaxed(val, base + ZX_CTRL); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci val = readl_relaxed(base + ZX_FIFOCTRL); 2038c2ecf20Sopenharmony_ci val &= ~ZX_FIFOCTRL_TX_DMA_EN_MASK; 2048c2ecf20Sopenharmony_ci if (on) 2058c2ecf20Sopenharmony_ci val |= ZX_FIFOCTRL_TX_DMA_EN; 2068c2ecf20Sopenharmony_ci writel_relaxed(val, base + ZX_FIFOCTRL); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int zx_spdif_trigger(struct snd_pcm_substream *substream, int cmd, 2108c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci u32 val; 2138c2ecf20Sopenharmony_ci struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); 2148c2ecf20Sopenharmony_ci int ret = 0; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci switch (cmd) { 2178c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2188c2ecf20Sopenharmony_ci val = readl_relaxed(zx_spdif->reg_base + ZX_FIFOCTRL); 2198c2ecf20Sopenharmony_ci val |= ZX_FIFOCTRL_TX_FIFO_RST; 2208c2ecf20Sopenharmony_ci writel_relaxed(val, zx_spdif->reg_base + ZX_FIFOCTRL); 2218c2ecf20Sopenharmony_ci fallthrough; 2228c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 2238c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 2248c2ecf20Sopenharmony_ci zx_spdif_cfg_tx(zx_spdif->reg_base, true); 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 2288c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 2298c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 2308c2ecf20Sopenharmony_ci zx_spdif_cfg_tx(zx_spdif->reg_base, false); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci default: 2348c2ecf20Sopenharmony_ci ret = -EINVAL; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return ret; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int zx_spdif_startup(struct snd_pcm_substream *substream, 2428c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return clk_prepare_enable(zx_spdif->dai_clk); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void zx_spdif_shutdown(struct snd_pcm_substream *substream, 2508c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci clk_disable_unprepare(zx_spdif->dai_clk); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define ZX_RATES \ 2588c2ecf20Sopenharmony_ci (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 2598c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ 2608c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci#define ZX_FORMAT \ 2638c2ecf20Sopenharmony_ci (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE \ 2648c2ecf20Sopenharmony_ci | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops zx_spdif_dai_ops = { 2678c2ecf20Sopenharmony_ci .trigger = zx_spdif_trigger, 2688c2ecf20Sopenharmony_ci .startup = zx_spdif_startup, 2698c2ecf20Sopenharmony_ci .shutdown = zx_spdif_shutdown, 2708c2ecf20Sopenharmony_ci .hw_params = zx_spdif_hw_params, 2718c2ecf20Sopenharmony_ci}; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver zx_spdif_dai = { 2748c2ecf20Sopenharmony_ci .name = "spdif", 2758c2ecf20Sopenharmony_ci .id = 0, 2768c2ecf20Sopenharmony_ci .probe = zx_spdif_dai_probe, 2778c2ecf20Sopenharmony_ci .playback = { 2788c2ecf20Sopenharmony_ci .channels_min = 1, 2798c2ecf20Sopenharmony_ci .channels_max = 2, 2808c2ecf20Sopenharmony_ci .rates = ZX_RATES, 2818c2ecf20Sopenharmony_ci .formats = ZX_FORMAT, 2828c2ecf20Sopenharmony_ci }, 2838c2ecf20Sopenharmony_ci .ops = &zx_spdif_dai_ops, 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver zx_spdif_component = { 2878c2ecf20Sopenharmony_ci .name = "spdif", 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void zx_spdif_dev_init(void __iomem *base) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci u32 val; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci writel_relaxed(0, base + ZX_CTRL); 2958c2ecf20Sopenharmony_ci writel_relaxed(0, base + ZX_INT_MASK); 2968c2ecf20Sopenharmony_ci writel_relaxed(0xf, base + ZX_INT_STATUS); 2978c2ecf20Sopenharmony_ci writel_relaxed(0x1, base + ZX_FIFOCTRL); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci val = readl_relaxed(base + ZX_FIFOCTRL); 3008c2ecf20Sopenharmony_ci val &= ~(ZX_FIFOCTRL_TXTH_MASK | ZX_FIFOCTRL_TX_FIFO_RST_MASK); 3018c2ecf20Sopenharmony_ci val |= ZX_FIFOCTRL_TXTH(8); 3028c2ecf20Sopenharmony_ci writel_relaxed(val, base + ZX_FIFOCTRL); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int zx_spdif_probe(struct platform_device *pdev) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct resource *res; 3088c2ecf20Sopenharmony_ci struct zx_spdif_info *zx_spdif; 3098c2ecf20Sopenharmony_ci int ret; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci zx_spdif = devm_kzalloc(&pdev->dev, sizeof(*zx_spdif), GFP_KERNEL); 3128c2ecf20Sopenharmony_ci if (!zx_spdif) 3138c2ecf20Sopenharmony_ci return -ENOMEM; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci zx_spdif->dai_clk = devm_clk_get(&pdev->dev, "tx"); 3168c2ecf20Sopenharmony_ci if (IS_ERR(zx_spdif->dai_clk)) { 3178c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Fail to get clk\n"); 3188c2ecf20Sopenharmony_ci return PTR_ERR(zx_spdif->dai_clk); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3228c2ecf20Sopenharmony_ci zx_spdif->mapbase = res->start; 3238c2ecf20Sopenharmony_ci zx_spdif->reg_base = devm_ioremap_resource(&pdev->dev, res); 3248c2ecf20Sopenharmony_ci if (IS_ERR(zx_spdif->reg_base)) { 3258c2ecf20Sopenharmony_ci return PTR_ERR(zx_spdif->reg_base); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci zx_spdif_dev_init(zx_spdif->reg_base); 3298c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, zx_spdif); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &zx_spdif_component, 3328c2ecf20Sopenharmony_ci &zx_spdif_dai, 1); 3338c2ecf20Sopenharmony_ci if (ret) { 3348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); 3358c2ecf20Sopenharmony_ci return ret; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 3398c2ecf20Sopenharmony_ci if (ret) 3408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return ret; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic const struct of_device_id zx_spdif_dt_ids[] = { 3468c2ecf20Sopenharmony_ci { .compatible = "zte,zx296702-spdif", }, 3478c2ecf20Sopenharmony_ci {} 3488c2ecf20Sopenharmony_ci}; 3498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, zx_spdif_dt_ids); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic struct platform_driver spdif_driver = { 3528c2ecf20Sopenharmony_ci .probe = zx_spdif_probe, 3538c2ecf20Sopenharmony_ci .driver = { 3548c2ecf20Sopenharmony_ci .name = "zx-spdif", 3558c2ecf20Sopenharmony_ci .of_match_table = zx_spdif_dt_ids, 3568c2ecf20Sopenharmony_ci }, 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cimodule_platform_driver(spdif_driver); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jun Nie <jun.nie@linaro.org>"); 3628c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ZTE SPDIF SoC DAI"); 3638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 364