162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/sound/soc/m8m/hi6210_i2s.c - I2S IP driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 Linaro, Ltd 662306a36Sopenharmony_ci * Author: Andy Green <andy.green@linaro.org> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * This driver only deals with S2 interface (BT) 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/clk.h> 1662306a36Sopenharmony_ci#include <linux/jiffies.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/gpio.h> 1962306a36Sopenharmony_ci#include <sound/core.h> 2062306a36Sopenharmony_ci#include <sound/pcm.h> 2162306a36Sopenharmony_ci#include <sound/pcm_params.h> 2262306a36Sopenharmony_ci#include <sound/dmaengine_pcm.h> 2362306a36Sopenharmony_ci#include <sound/initval.h> 2462306a36Sopenharmony_ci#include <sound/soc.h> 2562306a36Sopenharmony_ci#include <linux/interrupt.h> 2662306a36Sopenharmony_ci#include <linux/reset.h> 2762306a36Sopenharmony_ci#include <linux/of_address.h> 2862306a36Sopenharmony_ci#include <linux/of_irq.h> 2962306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 3062306a36Sopenharmony_ci#include <linux/reset-controller.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "hi6210-i2s.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct hi6210_i2s { 3562306a36Sopenharmony_ci struct device *dev; 3662306a36Sopenharmony_ci struct reset_control *rc; 3762306a36Sopenharmony_ci struct clk *clk[8]; 3862306a36Sopenharmony_ci int clocks; 3962306a36Sopenharmony_ci struct snd_soc_dai_driver dai; 4062306a36Sopenharmony_ci void __iomem *base; 4162306a36Sopenharmony_ci struct regmap *sysctrl; 4262306a36Sopenharmony_ci phys_addr_t base_phys; 4362306a36Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_data[2]; 4462306a36Sopenharmony_ci int clk_rate; 4562306a36Sopenharmony_ci spinlock_t lock; 4662306a36Sopenharmony_ci int rate; 4762306a36Sopenharmony_ci int format; 4862306a36Sopenharmony_ci u8 bits; 4962306a36Sopenharmony_ci u8 channels; 5062306a36Sopenharmony_ci u8 id; 5162306a36Sopenharmony_ci u8 channel_length; 5262306a36Sopenharmony_ci u8 use; 5362306a36Sopenharmony_ci u32 master:1; 5462306a36Sopenharmony_ci u32 status:1; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define SC_PERIPH_CLKEN1 0x210 5862306a36Sopenharmony_ci#define SC_PERIPH_CLKDIS1 0x214 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define SC_PERIPH_CLKEN3 0x230 6162306a36Sopenharmony_ci#define SC_PERIPH_CLKDIS3 0x234 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define SC_PERIPH_CLKEN12 0x270 6462306a36Sopenharmony_ci#define SC_PERIPH_CLKDIS12 0x274 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define SC_PERIPH_RSTEN1 0x310 6762306a36Sopenharmony_ci#define SC_PERIPH_RSTDIS1 0x314 6862306a36Sopenharmony_ci#define SC_PERIPH_RSTSTAT1 0x318 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define SC_PERIPH_RSTEN2 0x320 7162306a36Sopenharmony_ci#define SC_PERIPH_RSTDIS2 0x324 7262306a36Sopenharmony_ci#define SC_PERIPH_RSTSTAT2 0x328 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define SOC_PMCTRL_BBPPLLALIAS 0x48 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cienum { 7762306a36Sopenharmony_ci CLK_DACODEC, 7862306a36Sopenharmony_ci CLK_I2S_BASE, 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic inline void hi6210_write_reg(struct hi6210_i2s *i2s, int reg, u32 val) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci writel(val, i2s->base + reg); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic inline u32 hi6210_read_reg(struct hi6210_i2s *i2s, int reg) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci return readl(i2s->base + reg); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int hi6210_i2s_startup(struct snd_pcm_substream *substream, 9262306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 9562306a36Sopenharmony_ci int ret, n; 9662306a36Sopenharmony_ci u32 val; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* deassert reset on ABB */ 9962306a36Sopenharmony_ci regmap_read(i2s->sysctrl, SC_PERIPH_RSTSTAT2, &val); 10062306a36Sopenharmony_ci if (val & BIT(4)) 10162306a36Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS2, BIT(4)); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci for (n = 0; n < i2s->clocks; n++) { 10462306a36Sopenharmony_ci ret = clk_prepare_enable(i2s->clk[n]); 10562306a36Sopenharmony_ci if (ret) 10662306a36Sopenharmony_ci goto err_unprepare_clk; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci ret = clk_set_rate(i2s->clk[CLK_I2S_BASE], 49152000); 11062306a36Sopenharmony_ci if (ret) { 11162306a36Sopenharmony_ci dev_err(i2s->dev, "%s: setting 49.152MHz base rate failed %d\n", 11262306a36Sopenharmony_ci __func__, ret); 11362306a36Sopenharmony_ci goto err_unprepare_clk; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* enable clock before frequency division */ 11762306a36Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN12, BIT(9)); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* enable codec working clock / == "codec bus clock" */ 12062306a36Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN1, BIT(5)); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* deassert reset on codec / interface clock / working clock */ 12362306a36Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5)); 12462306a36Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS1, BIT(5)); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* not interested in i2s irqs */ 12762306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_CODEC_IRQ_MASK); 12862306a36Sopenharmony_ci val |= 0x3f; 12962306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_CODEC_IRQ_MASK, val); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* reset the stereo downlink fifo */ 13362306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1); 13462306a36Sopenharmony_ci val |= (BIT(5) | BIT(4)); 13562306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1); 13862306a36Sopenharmony_ci val &= ~(BIT(5) | BIT(4)); 13962306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_SW_RST_N); 14362306a36Sopenharmony_ci val &= ~(HII2S_SW_RST_N__ST_DL_WORDLEN_MASK << 14462306a36Sopenharmony_ci HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT); 14562306a36Sopenharmony_ci val |= (HII2S_BITS_16 << HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT); 14662306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_SW_RST_N, val); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_MISC_CFG); 14962306a36Sopenharmony_ci /* mux 11/12 = APB not i2s */ 15062306a36Sopenharmony_ci val &= ~HII2S_MISC_CFG__ST_DL_TEST_SEL; 15162306a36Sopenharmony_ci /* BT R ch 0 = mixer op of DACR ch */ 15262306a36Sopenharmony_ci val &= ~HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL; 15362306a36Sopenharmony_ci val &= ~HII2S_MISC_CFG__S2_DOUT_TEST_SEL; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci val |= HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL; 15662306a36Sopenharmony_ci /* BT L ch = 1 = mux 7 = "mixer output of DACL */ 15762306a36Sopenharmony_ci val |= HII2S_MISC_CFG__S2_DOUT_TEST_SEL; 15862306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_MISC_CFG, val); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_SW_RST_N); 16162306a36Sopenharmony_ci val |= HII2S_SW_RST_N__SW_RST_N; 16262306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_SW_RST_N, val); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cierr_unprepare_clk: 16762306a36Sopenharmony_ci while (n--) 16862306a36Sopenharmony_ci clk_disable_unprepare(i2s->clk[n]); 16962306a36Sopenharmony_ci return ret; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void hi6210_i2s_shutdown(struct snd_pcm_substream *substream, 17362306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 17662306a36Sopenharmony_ci int n; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci for (n = 0; n < i2s->clocks; n++) 17962306a36Sopenharmony_ci clk_disable_unprepare(i2s->clk[n]); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5)); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic void hi6210_i2s_txctrl(struct snd_soc_dai *cpu_dai, int on) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 18762306a36Sopenharmony_ci u32 val; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci spin_lock(&i2s->lock); 19062306a36Sopenharmony_ci if (on) { 19162306a36Sopenharmony_ci /* enable S2 TX */ 19262306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 19362306a36Sopenharmony_ci val |= HII2S_I2S_CFG__S2_IF_TX_EN; 19462306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 19562306a36Sopenharmony_ci } else { 19662306a36Sopenharmony_ci /* disable S2 TX */ 19762306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 19862306a36Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_IF_TX_EN; 19962306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci spin_unlock(&i2s->lock); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void hi6210_i2s_rxctrl(struct snd_soc_dai *cpu_dai, int on) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 20762306a36Sopenharmony_ci u32 val; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci spin_lock(&i2s->lock); 21062306a36Sopenharmony_ci if (on) { 21162306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 21262306a36Sopenharmony_ci val |= HII2S_I2S_CFG__S2_IF_RX_EN; 21362306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 21462306a36Sopenharmony_ci } else { 21562306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 21662306a36Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_IF_RX_EN; 21762306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci spin_unlock(&i2s->lock); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * We don't actually set the hardware until the hw_params 22862306a36Sopenharmony_ci * call, but we need to validate the user input here. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 23162306a36Sopenharmony_ci case SND_SOC_DAIFMT_BC_FC: 23262306a36Sopenharmony_ci case SND_SOC_DAIFMT_BP_FP: 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci default: 23562306a36Sopenharmony_ci return -EINVAL; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 23962306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 24062306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 24162306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 24262306a36Sopenharmony_ci break; 24362306a36Sopenharmony_ci default: 24462306a36Sopenharmony_ci return -EINVAL; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci i2s->format = fmt; 24862306a36Sopenharmony_ci i2s->master = (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == 24962306a36Sopenharmony_ci SND_SOC_DAIFMT_BP_FP; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int hi6210_i2s_hw_params(struct snd_pcm_substream *substream, 25562306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 25662306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev); 25962306a36Sopenharmony_ci u32 bits = 0, rate = 0, signed_data = 0, fmt = 0; 26062306a36Sopenharmony_ci u32 val; 26162306a36Sopenharmony_ci struct snd_dmaengine_dai_dma_data *dma_data; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci switch (params_format(params)) { 26462306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U16_LE: 26562306a36Sopenharmony_ci signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; 26662306a36Sopenharmony_ci fallthrough; 26762306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 26862306a36Sopenharmony_ci bits = HII2S_BITS_16; 26962306a36Sopenharmony_ci break; 27062306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_U24_LE: 27162306a36Sopenharmony_ci signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; 27262306a36Sopenharmony_ci fallthrough; 27362306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 27462306a36Sopenharmony_ci bits = HII2S_BITS_24; 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci default: 27762306a36Sopenharmony_ci dev_err(cpu_dai->dev, "Bad format\n"); 27862306a36Sopenharmony_ci return -EINVAL; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci switch (params_rate(params)) { 28362306a36Sopenharmony_ci case 8000: 28462306a36Sopenharmony_ci rate = HII2S_FS_RATE_8KHZ; 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci case 16000: 28762306a36Sopenharmony_ci rate = HII2S_FS_RATE_16KHZ; 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci case 32000: 29062306a36Sopenharmony_ci rate = HII2S_FS_RATE_32KHZ; 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci case 48000: 29362306a36Sopenharmony_ci rate = HII2S_FS_RATE_48KHZ; 29462306a36Sopenharmony_ci break; 29562306a36Sopenharmony_ci case 96000: 29662306a36Sopenharmony_ci rate = HII2S_FS_RATE_96KHZ; 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci case 192000: 29962306a36Sopenharmony_ci rate = HII2S_FS_RATE_192KHZ; 30062306a36Sopenharmony_ci break; 30162306a36Sopenharmony_ci default: 30262306a36Sopenharmony_ci dev_err(cpu_dai->dev, "Bad rate: %d\n", params_rate(params)); 30362306a36Sopenharmony_ci return -EINVAL; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!(params_channels(params))) { 30762306a36Sopenharmony_ci dev_err(cpu_dai->dev, "Bad channels\n"); 30862306a36Sopenharmony_ci return -EINVAL; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci switch (bits) { 31462306a36Sopenharmony_ci case HII2S_BITS_24: 31562306a36Sopenharmony_ci i2s->bits = 32; 31662306a36Sopenharmony_ci dma_data->addr_width = 3; 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci default: 31962306a36Sopenharmony_ci i2s->bits = 16; 32062306a36Sopenharmony_ci dma_data->addr_width = 2; 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci i2s->rate = params_rate(params); 32462306a36Sopenharmony_ci i2s->channels = params_channels(params); 32562306a36Sopenharmony_ci i2s->channel_length = i2s->channels * i2s->bits; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG); 32862306a36Sopenharmony_ci val &= ~((HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_MASK << 32962306a36Sopenharmony_ci HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) | 33062306a36Sopenharmony_ci (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_MASK << 33162306a36Sopenharmony_ci HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) | 33262306a36Sopenharmony_ci (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_MASK << 33362306a36Sopenharmony_ci HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) | 33462306a36Sopenharmony_ci (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_MASK << 33562306a36Sopenharmony_ci HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT)); 33662306a36Sopenharmony_ci val |= ((16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) | 33762306a36Sopenharmony_ci (30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) | 33862306a36Sopenharmony_ci (16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) | 33962306a36Sopenharmony_ci (30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT)); 34062306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG, val); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_IF_CLK_EN_CFG); 34462306a36Sopenharmony_ci val |= (BIT(19) | BIT(18) | BIT(17) | 34562306a36Sopenharmony_ci HII2S_IF_CLK_EN_CFG__S2_IF_CLK_EN | 34662306a36Sopenharmony_ci HII2S_IF_CLK_EN_CFG__S2_OL_MIXER_EN | 34762306a36Sopenharmony_ci HII2S_IF_CLK_EN_CFG__S2_OL_SRC_EN | 34862306a36Sopenharmony_ci HII2S_IF_CLK_EN_CFG__ST_DL_R_EN | 34962306a36Sopenharmony_ci HII2S_IF_CLK_EN_CFG__ST_DL_L_EN); 35062306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_IF_CLK_EN_CFG, val); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG); 35462306a36Sopenharmony_ci val &= ~(HII2S_DIG_FILTER_CLK_EN_CFG__DACR_SDM_EN | 35562306a36Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACR_HBF2I_EN | 35662306a36Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACR_AGC_EN | 35762306a36Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACL_SDM_EN | 35862306a36Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACL_HBF2I_EN | 35962306a36Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACL_AGC_EN); 36062306a36Sopenharmony_ci val |= (HII2S_DIG_FILTER_CLK_EN_CFG__DACR_MIXER_EN | 36162306a36Sopenharmony_ci HII2S_DIG_FILTER_CLK_EN_CFG__DACL_MIXER_EN); 36262306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG, val); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG); 36662306a36Sopenharmony_ci val &= ~(HII2S_DIG_FILTER_MODULE_CFG__DACR_MIXER_IN2_MUTE | 36762306a36Sopenharmony_ci HII2S_DIG_FILTER_MODULE_CFG__DACL_MIXER_IN2_MUTE); 36862306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG, val); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_MUX_TOP_MODULE_CFG); 37162306a36Sopenharmony_ci val &= ~(HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN1_MUTE | 37262306a36Sopenharmony_ci HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN2_MUTE | 37362306a36Sopenharmony_ci HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN1_MUTE | 37462306a36Sopenharmony_ci HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN2_MUTE); 37562306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci switch (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 37962306a36Sopenharmony_ci case SND_SOC_DAIFMT_BC_FC: 38062306a36Sopenharmony_ci i2s->master = false; 38162306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 38262306a36Sopenharmony_ci val |= HII2S_I2S_CFG__S2_MST_SLV; 38362306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case SND_SOC_DAIFMT_BP_FP: 38662306a36Sopenharmony_ci i2s->master = true; 38762306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 38862306a36Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_MST_SLV; 38962306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci default: 39262306a36Sopenharmony_ci WARN_ONCE(1, "Invalid i2s->fmt CLOCK_PROVIDER_MASK. This shouldn't happen\n"); 39362306a36Sopenharmony_ci return -EINVAL; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { 39762306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 39862306a36Sopenharmony_ci fmt = HII2S_FORMAT_I2S; 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 40162306a36Sopenharmony_ci fmt = HII2S_FORMAT_LEFT_JUST; 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 40462306a36Sopenharmony_ci fmt = HII2S_FORMAT_RIGHT_JUST; 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci default: 40762306a36Sopenharmony_ci WARN_ONCE(1, "Invalid i2s->fmt FORMAT_MASK. This shouldn't happen\n"); 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 41262306a36Sopenharmony_ci val &= ~(HII2S_I2S_CFG__S2_FUNC_MODE_MASK << 41362306a36Sopenharmony_ci HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT); 41462306a36Sopenharmony_ci val |= fmt << HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT; 41562306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_CLK_SEL); 41962306a36Sopenharmony_ci val &= ~(HII2S_CLK_SEL__I2S_BT_FM_SEL | /* BT gets the I2S */ 42062306a36Sopenharmony_ci HII2S_CLK_SEL__EXT_12_288MHZ_SEL); 42162306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_CLK_SEL, val); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci dma_data->maxburst = 2; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 42662306a36Sopenharmony_ci dma_data->addr = i2s->base_phys + HII2S_ST_DL_CHANNEL; 42762306a36Sopenharmony_ci else 42862306a36Sopenharmony_ci dma_data->addr = i2s->base_phys + HII2S_STEREO_UPLINK_CHANNEL; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci switch (i2s->channels) { 43162306a36Sopenharmony_ci case 1: 43262306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 43362306a36Sopenharmony_ci val |= HII2S_I2S_CFG__S2_FRAME_MODE; 43462306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci default: 43762306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 43862306a36Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_FRAME_MODE; 43962306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* clear loopback, set signed type and word length */ 44462306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_I2S_CFG); 44562306a36Sopenharmony_ci val &= ~HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT; 44662306a36Sopenharmony_ci val &= ~(HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_MASK << 44762306a36Sopenharmony_ci HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT); 44862306a36Sopenharmony_ci val &= ~(HII2S_I2S_CFG__S2_DIRECT_LOOP_MASK << 44962306a36Sopenharmony_ci HII2S_I2S_CFG__S2_DIRECT_LOOP_SHIFT); 45062306a36Sopenharmony_ci val |= signed_data; 45162306a36Sopenharmony_ci val |= (bits << HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT); 45262306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_I2S_CFG, val); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (!i2s->master) 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* set DAC and related units to correct rate */ 45962306a36Sopenharmony_ci val = hi6210_read_reg(i2s, HII2S_FS_CFG); 46062306a36Sopenharmony_ci val &= ~(HII2S_FS_CFG__FS_S2_MASK << HII2S_FS_CFG__FS_S2_SHIFT); 46162306a36Sopenharmony_ci val &= ~(HII2S_FS_CFG__FS_DACLR_MASK << HII2S_FS_CFG__FS_DACLR_SHIFT); 46262306a36Sopenharmony_ci val &= ~(HII2S_FS_CFG__FS_ST_DL_R_MASK << 46362306a36Sopenharmony_ci HII2S_FS_CFG__FS_ST_DL_R_SHIFT); 46462306a36Sopenharmony_ci val &= ~(HII2S_FS_CFG__FS_ST_DL_L_MASK << 46562306a36Sopenharmony_ci HII2S_FS_CFG__FS_ST_DL_L_SHIFT); 46662306a36Sopenharmony_ci val |= (rate << HII2S_FS_CFG__FS_S2_SHIFT); 46762306a36Sopenharmony_ci val |= (rate << HII2S_FS_CFG__FS_DACLR_SHIFT); 46862306a36Sopenharmony_ci val |= (rate << HII2S_FS_CFG__FS_ST_DL_R_SHIFT); 46962306a36Sopenharmony_ci val |= (rate << HII2S_FS_CFG__FS_ST_DL_L_SHIFT); 47062306a36Sopenharmony_ci hi6210_write_reg(i2s, HII2S_FS_CFG, val); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic int hi6210_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 47662306a36Sopenharmony_ci struct snd_soc_dai *cpu_dai) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci pr_debug("%s\n", __func__); 47962306a36Sopenharmony_ci switch (cmd) { 48062306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 48162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 48262306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 48362306a36Sopenharmony_ci hi6210_i2s_rxctrl(cpu_dai, 1); 48462306a36Sopenharmony_ci else 48562306a36Sopenharmony_ci hi6210_i2s_txctrl(cpu_dai, 1); 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 48862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 48962306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 49062306a36Sopenharmony_ci hi6210_i2s_rxctrl(cpu_dai, 0); 49162306a36Sopenharmony_ci else 49262306a36Sopenharmony_ci hi6210_i2s_txctrl(cpu_dai, 0); 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci default: 49562306a36Sopenharmony_ci dev_err(cpu_dai->dev, "unknown cmd\n"); 49662306a36Sopenharmony_ci return -EINVAL; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci return 0; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic int hi6210_i2s_dai_probe(struct snd_soc_dai *dai) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct hi6210_i2s *i2s = snd_soc_dai_get_drvdata(dai); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci snd_soc_dai_init_dma_data(dai, 50662306a36Sopenharmony_ci &i2s->dma_data[SNDRV_PCM_STREAM_PLAYBACK], 50762306a36Sopenharmony_ci &i2s->dma_data[SNDRV_PCM_STREAM_CAPTURE]); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci} 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic const struct snd_soc_dai_ops hi6210_i2s_dai_ops = { 51462306a36Sopenharmony_ci .probe = hi6210_i2s_dai_probe, 51562306a36Sopenharmony_ci .trigger = hi6210_i2s_trigger, 51662306a36Sopenharmony_ci .hw_params = hi6210_i2s_hw_params, 51762306a36Sopenharmony_ci .set_fmt = hi6210_i2s_set_fmt, 51862306a36Sopenharmony_ci .startup = hi6210_i2s_startup, 51962306a36Sopenharmony_ci .shutdown = hi6210_i2s_shutdown, 52062306a36Sopenharmony_ci}; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic const struct snd_soc_dai_driver hi6210_i2s_dai_init = { 52362306a36Sopenharmony_ci .playback = { 52462306a36Sopenharmony_ci .channels_min = 2, 52562306a36Sopenharmony_ci .channels_max = 2, 52662306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 52762306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE, 52862306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 52962306a36Sopenharmony_ci }, 53062306a36Sopenharmony_ci .capture = { 53162306a36Sopenharmony_ci .channels_min = 2, 53262306a36Sopenharmony_ci .channels_max = 2, 53362306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 53462306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_LE, 53562306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 53662306a36Sopenharmony_ci }, 53762306a36Sopenharmony_ci .ops = &hi6210_i2s_dai_ops, 53862306a36Sopenharmony_ci}; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cistatic const struct snd_soc_component_driver hi6210_i2s_i2s_comp = { 54162306a36Sopenharmony_ci .name = "hi6210_i2s-i2s", 54262306a36Sopenharmony_ci .legacy_dai_naming = 1, 54362306a36Sopenharmony_ci}; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic int hi6210_i2s_probe(struct platform_device *pdev) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 54862306a36Sopenharmony_ci struct device *dev = &pdev->dev; 54962306a36Sopenharmony_ci struct hi6210_i2s *i2s; 55062306a36Sopenharmony_ci struct resource *res; 55162306a36Sopenharmony_ci int ret; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); 55462306a36Sopenharmony_ci if (!i2s) 55562306a36Sopenharmony_ci return -ENOMEM; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci i2s->dev = dev; 55862306a36Sopenharmony_ci spin_lock_init(&i2s->lock); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 56162306a36Sopenharmony_ci if (IS_ERR(i2s->base)) 56262306a36Sopenharmony_ci return PTR_ERR(i2s->base); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci i2s->base_phys = (phys_addr_t)res->start; 56562306a36Sopenharmony_ci i2s->dai = hi6210_i2s_dai_init; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci dev_set_drvdata(dev, i2s); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci i2s->sysctrl = syscon_regmap_lookup_by_phandle(node, 57062306a36Sopenharmony_ci "hisilicon,sysctrl-syscon"); 57162306a36Sopenharmony_ci if (IS_ERR(i2s->sysctrl)) 57262306a36Sopenharmony_ci return PTR_ERR(i2s->sysctrl); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci i2s->clk[CLK_DACODEC] = devm_clk_get(dev, "dacodec"); 57562306a36Sopenharmony_ci if (IS_ERR(i2s->clk[CLK_DACODEC])) 57662306a36Sopenharmony_ci return PTR_ERR(i2s->clk[CLK_DACODEC]); 57762306a36Sopenharmony_ci i2s->clocks++; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci i2s->clk[CLK_I2S_BASE] = devm_clk_get(dev, "i2s-base"); 58062306a36Sopenharmony_ci if (IS_ERR(i2s->clk[CLK_I2S_BASE])) 58162306a36Sopenharmony_ci return PTR_ERR(i2s->clk[CLK_I2S_BASE]); 58262306a36Sopenharmony_ci i2s->clocks++; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); 58562306a36Sopenharmony_ci if (ret) 58662306a36Sopenharmony_ci return ret; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci ret = devm_snd_soc_register_component(dev, &hi6210_i2s_i2s_comp, 58962306a36Sopenharmony_ci &i2s->dai, 1); 59062306a36Sopenharmony_ci return ret; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic const struct of_device_id hi6210_i2s_dt_ids[] = { 59462306a36Sopenharmony_ci { .compatible = "hisilicon,hi6210-i2s" }, 59562306a36Sopenharmony_ci { /* sentinel */ } 59662306a36Sopenharmony_ci}; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, hi6210_i2s_dt_ids); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic struct platform_driver hi6210_i2s_driver = { 60162306a36Sopenharmony_ci .probe = hi6210_i2s_probe, 60262306a36Sopenharmony_ci .driver = { 60362306a36Sopenharmony_ci .name = "hi6210_i2s", 60462306a36Sopenharmony_ci .of_match_table = hi6210_i2s_dt_ids, 60562306a36Sopenharmony_ci }, 60662306a36Sopenharmony_ci}; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cimodule_platform_driver(hi6210_i2s_driver); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ciMODULE_DESCRIPTION("Hisilicon HI6210 I2S driver"); 61162306a36Sopenharmony_ciMODULE_AUTHOR("Andy Green <andy.green@linaro.org>"); 61262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 613