18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/sound/soc/m8m/hi6210_i2s.c - I2S IP driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 Linaro, Ltd 68c2ecf20Sopenharmony_ci * Author: Andy Green <andy.green@linaro.org> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This driver only deals with S2 interface (BT) 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 178c2ecf20Sopenharmony_ci#include <linux/io.h> 188c2ecf20Sopenharmony_ci#include <linux/gpio.h> 198c2ecf20Sopenharmony_ci#include <sound/core.h> 208c2ecf20Sopenharmony_ci#include <sound/pcm.h> 218c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 228c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 238c2ecf20Sopenharmony_ci#include <sound/initval.h> 248c2ecf20Sopenharmony_ci#include <sound/soc.h> 258c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 268c2ecf20Sopenharmony_ci#include <linux/reset.h> 278c2ecf20Sopenharmony_ci#include <linux/of_address.h> 288c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 298c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 308c2ecf20Sopenharmony_ci#include <linux/reset-controller.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "hi6210-i2s.h" 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct hi6210_i2s { 358c2ecf20Sopenharmony_ci struct device *dev; 368c2ecf20Sopenharmony_ci struct reset_control *rc; 378c2ecf20Sopenharmony_ci struct clk *clk[8]; 388c2ecf20Sopenharmony_ci int clocks; 398c2ecf20Sopenharmony_ci struct snd_soc_dai_driver dai; 408c2ecf20Sopenharmony_ci void __iomem *base; 418c2ecf20Sopenharmony_ci struct regmap *sysctrl; 428c2ecf20Sopenharmony_ci phys_addr_t base_phys; 438c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_data[2]; 448c2ecf20Sopenharmony_ci int clk_rate; 458c2ecf20Sopenharmony_ci spinlock_t lock; 468c2ecf20Sopenharmony_ci int rate; 478c2ecf20Sopenharmony_ci int format; 488c2ecf20Sopenharmony_ci u8 bits; 498c2ecf20Sopenharmony_ci u8 channels; 508c2ecf20Sopenharmony_ci u8 id; 518c2ecf20Sopenharmony_ci u8 channel_length; 528c2ecf20Sopenharmony_ci u8 use; 538c2ecf20Sopenharmony_ci u32 master:1; 548c2ecf20Sopenharmony_ci u32 status:1; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKEN1 0x210 588c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKDIS1 0x214 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKEN3 0x230 618c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKDIS3 0x234 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKEN12 0x270 648c2ecf20Sopenharmony_ci#define SC_PERIPH_CLKDIS12 0x274 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTEN1 0x310 678c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTDIS1 0x314 688c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTSTAT1 0x318 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTEN2 0x320 718c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTDIS2 0x324 728c2ecf20Sopenharmony_ci#define SC_PERIPH_RSTSTAT2 0x328 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define SOC_PMCTRL_BBPPLLALIAS 0x48 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cienum { 778c2ecf20Sopenharmony_ci CLK_DACODEC, 788c2ecf20Sopenharmony_ci CLK_I2S_BASE, 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic inline void hi6210_write_reg(struct hi6210_i2s *i2s, int reg, u32 val) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci writel(val, i2s->base + reg); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic inline u32 hi6210_read_reg(struct hi6210_i2s *i2s, int reg) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci return readl(i2s->base + reg); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int hi6210_i2s_startup(struct snd_pcm_substream *substream, 928c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 958c2ecf20Sopenharmony_ci int ret, n; 968c2ecf20Sopenharmony_ci u32 val; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* deassert reset on ABB */ 998c2ecf20Sopenharmony_ci regmap_read(i2s->sysctrl, SC_PERIPH_RSTSTAT2, &val); 1008c2ecf20Sopenharmony_ci if (val & BIT(4)) 1018c2ecf20Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS2, BIT(4)); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci for (n = 0; n < i2s->clocks; n++) { 1048c2ecf20Sopenharmony_ci ret = clk_prepare_enable(i2s->clk[n]); 1058c2ecf20Sopenharmony_ci if (ret) 1068c2ecf20Sopenharmony_ci goto err_unprepare_clk; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci ret = clk_set_rate(i2s->clk[CLK_I2S_BASE], 49152000); 1108c2ecf20Sopenharmony_ci if (ret) { 1118c2ecf20Sopenharmony_ci dev_err(i2s->dev, "%s: setting 49.152MHz base rate failed %d\n", 1128c2ecf20Sopenharmony_ci __func__, ret); 1138c2ecf20Sopenharmony_ci goto err_unprepare_clk; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* enable clock before frequency division */ 1178c2ecf20Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN12, BIT(9)); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* enable codec working clock / == "codec bus clock" */ 1208c2ecf20Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN1, BIT(5)); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* deassert reset on codec / interface clock / working clock */ 1238c2ecf20Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5)); 1248c2ecf20Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS1, BIT(5)); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* not interested in i2s irqs */ 1278c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_CODEC_IRQ_MASK); 1288c2ecf20Sopenharmony_ci val |= 0x3f; 1298c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_CODEC_IRQ_MASK, val); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* reset the stereo downlink fifo */ 1338c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1); 1348c2ecf20Sopenharmony_ci val |= (BIT(5) | BIT(4)); 1358c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1); 1388c2ecf20Sopenharmony_ci val &= ~(BIT(5) | BIT(4)); 1398c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_SW_RST_N); 1438c2ecf20Sopenharmony_ci val &= ~(HII2S_SW_RST_N__ST_DL_WORDLEN_MASK << 1448c2ecf20Sopenharmony_ci HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT); 1458c2ecf20Sopenharmony_ci val |= (HII2S_BITS_16 << HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT); 1468c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_SW_RST_N, val); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_MISC_CFG); 1498c2ecf20Sopenharmony_ci /* mux 11/12 = APB not i2s */ 1508c2ecf20Sopenharmony_ci val &= ~HII2S_MISC_CFG__ST_DL_TEST_SEL; 1518c2ecf20Sopenharmony_ci /* BT R ch 0 = mixer op of DACR ch */ 1528c2ecf20Sopenharmony_ci val &= ~HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL; 1538c2ecf20Sopenharmony_ci val &= ~HII2S_MISC_CFG__S2_DOUT_TEST_SEL; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci val |= HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL; 1568c2ecf20Sopenharmony_ci /* BT L ch = 1 = mux 7 = "mixer output of DACL */ 1578c2ecf20Sopenharmony_ci val |= HII2S_MISC_CFG__S2_DOUT_TEST_SEL; 1588c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_MISC_CFG, val); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_SW_RST_N); 1618c2ecf20Sopenharmony_ci val |= HII2S_SW_RST_N__SW_RST_N; 1628c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_SW_RST_N, val); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cierr_unprepare_clk: 1678c2ecf20Sopenharmony_ci while (n--) 1688c2ecf20Sopenharmony_ci clk_disable_unprepare(i2s->clk[n]); 1698c2ecf20Sopenharmony_ci return ret; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void hi6210_i2s_shutdown(struct snd_pcm_substream *substream, 1738c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 1768c2ecf20Sopenharmony_ci int n; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci for (n = 0; n < i2s->clocks; n++) 1798c2ecf20Sopenharmony_ci clk_disable_unprepare(i2s->clk[n]); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5)); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic void hi6210_i2s_txctrl(struct snd_soc_dai *cpu_dai, int on) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 1878c2ecf20Sopenharmony_ci u32 val; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci spin_lock(&i2s->lock); 1908c2ecf20Sopenharmony_ci if (on) { 1918c2ecf20Sopenharmony_ci /* enable S2 TX */ 1928c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 1938c2ecf20Sopenharmony_ci val |= HII2S_I2S_CFG__S2_IF_TX_EN; 1948c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 1958c2ecf20Sopenharmony_ci } else { 1968c2ecf20Sopenharmony_ci /* disable S2 TX */ 1978c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 1988c2ecf20Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_IF_TX_EN; 1998c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci spin_unlock(&i2s->lock); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic void hi6210_i2s_rxctrl(struct snd_soc_dai *cpu_dai, int on) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 2078c2ecf20Sopenharmony_ci u32 val; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci spin_lock(&i2s->lock); 2108c2ecf20Sopenharmony_ci if (on) { 2118c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 2128c2ecf20Sopenharmony_ci val |= HII2S_I2S_CFG__S2_IF_RX_EN; 2138c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 2148c2ecf20Sopenharmony_ci } else { 2158c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 2168c2ecf20Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_IF_RX_EN; 2178c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci spin_unlock(&i2s->lock); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* 2278c2ecf20Sopenharmony_ci * We don't actually set the hardware until the hw_params 2288c2ecf20Sopenharmony_ci * call, but we need to validate the user input here. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 2318c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 2328c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci default: 2358c2ecf20Sopenharmony_ci return -EINVAL; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 2398c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 2408c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 2418c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci default: 2448c2ecf20Sopenharmony_ci return -EINVAL; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci i2s->format = fmt; 2488c2ecf20Sopenharmony_ci i2s->master = (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) == 2498c2ecf20Sopenharmony_ci SND_SOC_DAIFMT_CBS_CFS; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int hi6210_i2s_hw_params(struct snd_pcm_substream *substream, 2558c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 2568c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 2598c2ecf20Sopenharmony_ci u32 bits = 0, rate = 0, signed_data = 0, fmt = 0; 2608c2ecf20Sopenharmony_ci u32 val; 2618c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci switch (params_format(params)) { 2648c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U16_LE: 2658c2ecf20Sopenharmony_ci signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; 2668c2ecf20Sopenharmony_ci fallthrough; 2678c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 2688c2ecf20Sopenharmony_ci bits = HII2S_BITS_16; 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_U24_LE: 2718c2ecf20Sopenharmony_ci signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; 2728c2ecf20Sopenharmony_ci fallthrough; 2738c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 2748c2ecf20Sopenharmony_ci bits = HII2S_BITS_24; 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci default: 2778c2ecf20Sopenharmony_ci dev_err(cpu_dai->dev, "Bad format\n"); 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci switch (params_rate(params)) { 2838c2ecf20Sopenharmony_ci case 8000: 2848c2ecf20Sopenharmony_ci rate = HII2S_FS_RATE_8KHZ; 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci case 16000: 2878c2ecf20Sopenharmony_ci rate = HII2S_FS_RATE_16KHZ; 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci case 32000: 2908c2ecf20Sopenharmony_ci rate = HII2S_FS_RATE_32KHZ; 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci case 48000: 2938c2ecf20Sopenharmony_ci rate = HII2S_FS_RATE_48KHZ; 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci case 96000: 2968c2ecf20Sopenharmony_ci rate = HII2S_FS_RATE_96KHZ; 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci case 192000: 2998c2ecf20Sopenharmony_ci rate = HII2S_FS_RATE_192KHZ; 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci default: 3028c2ecf20Sopenharmony_ci dev_err(cpu_dai->dev, "Bad rate: %d\n", params_rate(params)); 3038c2ecf20Sopenharmony_ci return -EINVAL; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (!(params_channels(params))) { 3078c2ecf20Sopenharmony_ci dev_err(cpu_dai->dev, "Bad channels\n"); 3088c2ecf20Sopenharmony_ci return -EINVAL; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci switch (bits) { 3148c2ecf20Sopenharmony_ci case HII2S_BITS_24: 3158c2ecf20Sopenharmony_ci i2s->bits = 32; 3168c2ecf20Sopenharmony_ci dma_data->addr_width = 3; 3178c2ecf20Sopenharmony_ci break; 3188c2ecf20Sopenharmony_ci default: 3198c2ecf20Sopenharmony_ci i2s->bits = 16; 3208c2ecf20Sopenharmony_ci dma_data->addr_width = 2; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci i2s->rate = params_rate(params); 3248c2ecf20Sopenharmony_ci i2s->channels = params_channels(params); 3258c2ecf20Sopenharmony_ci i2s->channel_length = i2s->channels * i2s->bits; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG); 3288c2ecf20Sopenharmony_ci val &= ~((HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_MASK << 3298c2ecf20Sopenharmony_ci HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) | 3308c2ecf20Sopenharmony_ci (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_MASK << 3318c2ecf20Sopenharmony_ci HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) | 3328c2ecf20Sopenharmony_ci (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_MASK << 3338c2ecf20Sopenharmony_ci HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) | 3348c2ecf20Sopenharmony_ci (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_MASK << 3358c2ecf20Sopenharmony_ci HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT)); 3368c2ecf20Sopenharmony_ci val |= ((16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) | 3378c2ecf20Sopenharmony_ci (30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) | 3388c2ecf20Sopenharmony_ci (16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) | 3398c2ecf20Sopenharmony_ci (30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT)); 3408c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG, val); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_IF_CLK_EN_CFG); 3448c2ecf20Sopenharmony_ci val |= (BIT(19) | BIT(18) | BIT(17) | 3458c2ecf20Sopenharmony_ci HII2S_IF_CLK_EN_CFG__S2_IF_CLK_EN | 3468c2ecf20Sopenharmony_ci HII2S_IF_CLK_EN_CFG__S2_OL_MIXER_EN | 3478c2ecf20Sopenharmony_ci HII2S_IF_CLK_EN_CFG__S2_OL_SRC_EN | 3488c2ecf20Sopenharmony_ci HII2S_IF_CLK_EN_CFG__ST_DL_R_EN | 3498c2ecf20Sopenharmony_ci HII2S_IF_CLK_EN_CFG__ST_DL_L_EN); 3508c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_IF_CLK_EN_CFG, val); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG); 3548c2ecf20Sopenharmony_ci val &= ~(HII2S_DIG_FILTER_CLK_EN_CFG__DACR_SDM_EN | 3558c2ecf20Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACR_HBF2I_EN | 3568c2ecf20Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACR_AGC_EN | 3578c2ecf20Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACL_SDM_EN | 3588c2ecf20Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACL_HBF2I_EN | 3598c2ecf20Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACL_AGC_EN); 3608c2ecf20Sopenharmony_ci val |= (HII2S_DIG_FILTER_CLK_EN_CFG__DACR_MIXER_EN | 3618c2ecf20Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACL_MIXER_EN); 3628c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG, val); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG); 3668c2ecf20Sopenharmony_ci val &= ~(HII2S_DIG_FILTER_MODULE_CFG__DACR_MIXER_IN2_MUTE | 3678c2ecf20Sopenharmony_ci HII2S_DIG_FILTER_MODULE_CFG__DACL_MIXER_IN2_MUTE); 3688c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG, val); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_MUX_TOP_MODULE_CFG); 3718c2ecf20Sopenharmony_ci val &= ~(HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN1_MUTE | 3728c2ecf20Sopenharmony_ci HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN2_MUTE | 3738c2ecf20Sopenharmony_ci HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN1_MUTE | 3748c2ecf20Sopenharmony_ci HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN2_MUTE); 3758c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci switch (i2s->format & SND_SOC_DAIFMT_MASTER_MASK) { 3798c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 3808c2ecf20Sopenharmony_ci i2s->master = false; 3818c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 3828c2ecf20Sopenharmony_ci val |= HII2S_I2S_CFG__S2_MST_SLV; 3838c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBS_CFS: 3868c2ecf20Sopenharmony_ci i2s->master = true; 3878c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 3888c2ecf20Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_MST_SLV; 3898c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci default: 3928c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid i2s->fmt MASTER_MASK. This shouldn't happen\n"); 3938c2ecf20Sopenharmony_ci return -EINVAL; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { 3978c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 3988c2ecf20Sopenharmony_ci fmt = HII2S_FORMAT_I2S; 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 4018c2ecf20Sopenharmony_ci fmt = HII2S_FORMAT_LEFT_JUST; 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 4048c2ecf20Sopenharmony_ci fmt = HII2S_FORMAT_RIGHT_JUST; 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci default: 4078c2ecf20Sopenharmony_ci WARN_ONCE(1, "Invalid i2s->fmt FORMAT_MASK. This shouldn't happen\n"); 4088c2ecf20Sopenharmony_ci return -EINVAL; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 4128c2ecf20Sopenharmony_ci val &= ~(HII2S_I2S_CFG__S2_FUNC_MODE_MASK << 4138c2ecf20Sopenharmony_ci HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT); 4148c2ecf20Sopenharmony_ci val |= fmt << HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT; 4158c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_CLK_SEL); 4198c2ecf20Sopenharmony_ci val &= ~(HII2S_CLK_SEL__I2S_BT_FM_SEL | /* BT gets the I2S */ 4208c2ecf20Sopenharmony_ci HII2S_CLK_SEL__EXT_12_288MHZ_SEL); 4218c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_CLK_SEL, val); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci dma_data->maxburst = 2; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 4268c2ecf20Sopenharmony_ci dma_data->addr = i2s->base_phys + HII2S_ST_DL_CHANNEL; 4278c2ecf20Sopenharmony_ci else 4288c2ecf20Sopenharmony_ci dma_data->addr = i2s->base_phys + HII2S_STEREO_UPLINK_CHANNEL; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci switch (i2s->channels) { 4318c2ecf20Sopenharmony_ci case 1: 4328c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 4338c2ecf20Sopenharmony_ci val |= HII2S_I2S_CFG__S2_FRAME_MODE; 4348c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci default: 4378c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 4388c2ecf20Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_FRAME_MODE; 4398c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 4408c2ecf20Sopenharmony_ci break; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* clear loopback, set signed type and word length */ 4448c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 4458c2ecf20Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; 4468c2ecf20Sopenharmony_ci val &= ~(HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_MASK << 4478c2ecf20Sopenharmony_ci HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT); 4488c2ecf20Sopenharmony_ci val &= ~(HII2S_I2S_CFG__S2_DIRECT_LOOP_MASK << 4498c2ecf20Sopenharmony_ci HII2S_I2S_CFG__S2_DIRECT_LOOP_SHIFT); 4508c2ecf20Sopenharmony_ci val |= signed_data; 4518c2ecf20Sopenharmony_ci val |= (bits << HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT); 4528c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (!i2s->master) 4568c2ecf20Sopenharmony_ci return 0; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* set DAC and related units to correct rate */ 4598c2ecf20Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_FS_CFG); 4608c2ecf20Sopenharmony_ci val &= ~(HII2S_FS_CFG__FS_S2_MASK << HII2S_FS_CFG__FS_S2_SHIFT); 4618c2ecf20Sopenharmony_ci val &= ~(HII2S_FS_CFG__FS_DACLR_MASK << HII2S_FS_CFG__FS_DACLR_SHIFT); 4628c2ecf20Sopenharmony_ci val &= ~(HII2S_FS_CFG__FS_ST_DL_R_MASK << 4638c2ecf20Sopenharmony_ci HII2S_FS_CFG__FS_ST_DL_R_SHIFT); 4648c2ecf20Sopenharmony_ci val &= ~(HII2S_FS_CFG__FS_ST_DL_L_MASK << 4658c2ecf20Sopenharmony_ci HII2S_FS_CFG__FS_ST_DL_L_SHIFT); 4668c2ecf20Sopenharmony_ci val |= (rate << HII2S_FS_CFG__FS_S2_SHIFT); 4678c2ecf20Sopenharmony_ci val |= (rate << HII2S_FS_CFG__FS_DACLR_SHIFT); 4688c2ecf20Sopenharmony_ci val |= (rate << HII2S_FS_CFG__FS_ST_DL_R_SHIFT); 4698c2ecf20Sopenharmony_ci val |= (rate << HII2S_FS_CFG__FS_ST_DL_L_SHIFT); 4708c2ecf20Sopenharmony_ci hi6210_write_reg(i2s, HII2S_FS_CFG, val); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int hi6210_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 4768c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci pr_debug("%s\n", __func__); 4798c2ecf20Sopenharmony_ci switch (cmd) { 4808c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 4818c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 4828c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 4838c2ecf20Sopenharmony_ci hi6210_i2s_rxctrl(cpu_dai, 1); 4848c2ecf20Sopenharmony_ci else 4858c2ecf20Sopenharmony_ci hi6210_i2s_txctrl(cpu_dai, 1); 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 4888c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 4898c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 4908c2ecf20Sopenharmony_ci hi6210_i2s_rxctrl(cpu_dai, 0); 4918c2ecf20Sopenharmony_ci else 4928c2ecf20Sopenharmony_ci hi6210_i2s_txctrl(cpu_dai, 0); 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci default: 4958c2ecf20Sopenharmony_ci dev_err(cpu_dai->dev, "unknown cmd\n"); 4968c2ecf20Sopenharmony_ci return -EINVAL; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int hi6210_i2s_dai_probe(struct snd_soc_dai *dai) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct hi6210_i2s *i2s = snd_soc_dai_get_drvdata(dai); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, 5068c2ecf20Sopenharmony_ci &i2s->dma_data[SNDRV_PCM_STREAM_PLAYBACK], 5078c2ecf20Sopenharmony_ci &i2s->dma_data[SNDRV_PCM_STREAM_CAPTURE]); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { 5148c2ecf20Sopenharmony_ci .trigger = hi6210_i2s_trigger, 5158c2ecf20Sopenharmony_ci .hw_params = hi6210_i2s_hw_params, 5168c2ecf20Sopenharmony_ci .set_fmt = hi6210_i2s_set_fmt, 5178c2ecf20Sopenharmony_ci .startup = hi6210_i2s_startup, 5188c2ecf20Sopenharmony_ci .shutdown = hi6210_i2s_shutdown, 5198c2ecf20Sopenharmony_ci}; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_driver hi6210_i2s_dai_init = { 5228c2ecf20Sopenharmony_ci .probe = hi6210_i2s_dai_probe, 5238c2ecf20Sopenharmony_ci .playback = { 5248c2ecf20Sopenharmony_ci .channels_min = 2, 5258c2ecf20Sopenharmony_ci .channels_max = 2, 5268c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 5278c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE, 5288c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 5298c2ecf20Sopenharmony_ci }, 5308c2ecf20Sopenharmony_ci .capture = { 5318c2ecf20Sopenharmony_ci .channels_min = 2, 5328c2ecf20Sopenharmony_ci .channels_max = 2, 5338c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 5348c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE, 5358c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 5368c2ecf20Sopenharmony_ci }, 5378c2ecf20Sopenharmony_ci .ops = &hi6210_i2s_dai_ops, 5388c2ecf20Sopenharmony_ci}; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver hi6210_i2s_i2s_comp = { 5418c2ecf20Sopenharmony_ci .name = "hi6210_i2s-i2s", 5428c2ecf20Sopenharmony_ci}; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic int hi6210_i2s_probe(struct platform_device *pdev) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 5478c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5488c2ecf20Sopenharmony_ci struct hi6210_i2s *i2s; 5498c2ecf20Sopenharmony_ci struct resource *res; 5508c2ecf20Sopenharmony_ci int ret; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); 5538c2ecf20Sopenharmony_ci if (!i2s) 5548c2ecf20Sopenharmony_ci return -ENOMEM; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci i2s->dev = dev; 5578c2ecf20Sopenharmony_ci spin_lock_init(&i2s->lock); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5608c2ecf20Sopenharmony_ci i2s->base = devm_ioremap_resource(dev, res); 5618c2ecf20Sopenharmony_ci if (IS_ERR(i2s->base)) 5628c2ecf20Sopenharmony_ci return PTR_ERR(i2s->base); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci i2s->base_phys = (phys_addr_t)res->start; 5658c2ecf20Sopenharmony_ci i2s->dai = hi6210_i2s_dai_init; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci dev_set_drvdata(dev, i2s); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci i2s->sysctrl = syscon_regmap_lookup_by_phandle(node, 5708c2ecf20Sopenharmony_ci "hisilicon,sysctrl-syscon"); 5718c2ecf20Sopenharmony_ci if (IS_ERR(i2s->sysctrl)) 5728c2ecf20Sopenharmony_ci return PTR_ERR(i2s->sysctrl); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci i2s->clk[CLK_DACODEC] = devm_clk_get(dev, "dacodec"); 5758c2ecf20Sopenharmony_ci if (IS_ERR(i2s->clk[CLK_DACODEC])) 5768c2ecf20Sopenharmony_ci return PTR_ERR(i2s->clk[CLK_DACODEC]); 5778c2ecf20Sopenharmony_ci i2s->clocks++; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci i2s->clk[CLK_I2S_BASE] = devm_clk_get(dev, "i2s-base"); 5808c2ecf20Sopenharmony_ci if (IS_ERR(i2s->clk[CLK_I2S_BASE])) 5818c2ecf20Sopenharmony_ci return PTR_ERR(i2s->clk[CLK_I2S_BASE]); 5828c2ecf20Sopenharmony_ci i2s->clocks++; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); 5858c2ecf20Sopenharmony_ci if (ret) 5868c2ecf20Sopenharmony_ci return ret; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &hi6210_i2s_i2s_comp, 5898c2ecf20Sopenharmony_ci &i2s->dai, 1); 5908c2ecf20Sopenharmony_ci return ret; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic const struct of_device_id hi6210_i2s_dt_ids[] = { 5948c2ecf20Sopenharmony_ci { .compatible = "hisilicon,hi6210-i2s" }, 5958c2ecf20Sopenharmony_ci { /* sentinel */ } 5968c2ecf20Sopenharmony_ci}; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, hi6210_i2s_dt_ids); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic struct platform_driver hi6210_i2s_driver = { 6018c2ecf20Sopenharmony_ci .probe = hi6210_i2s_probe, 6028c2ecf20Sopenharmony_ci .driver = { 6038c2ecf20Sopenharmony_ci .name = "hi6210_i2s", 6048c2ecf20Sopenharmony_ci .of_match_table = hi6210_i2s_dt_ids, 6058c2ecf20Sopenharmony_ci }, 6068c2ecf20Sopenharmony_ci}; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cimodule_platform_driver(hi6210_i2s_driver); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Hisilicon HI6210 I2S driver"); 6118c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andy Green <andy.green@linaro.org>"); 6128c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 613