18e8e69d6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20bf750f4SAndy Green /*
30bf750f4SAndy Green * linux/sound/soc/m8m/hi6210_i2s.c - I2S IP driver
40bf750f4SAndy Green *
50bf750f4SAndy Green * Copyright (C) 2015 Linaro, Ltd
60bf750f4SAndy Green * Author: Andy Green <andy.green@linaro.org>
70bf750f4SAndy Green *
80bf750f4SAndy Green * This driver only deals with S2 interface (BT)
90bf750f4SAndy Green */
100bf750f4SAndy Green
110bf750f4SAndy Green #include <linux/init.h>
120bf750f4SAndy Green #include <linux/module.h>
130bf750f4SAndy Green #include <linux/device.h>
140bf750f4SAndy Green #include <linux/delay.h>
150bf750f4SAndy Green #include <linux/clk.h>
160bf750f4SAndy Green #include <linux/jiffies.h>
170bf750f4SAndy Green #include <linux/io.h>
180bf750f4SAndy Green #include <sound/core.h>
190bf750f4SAndy Green #include <sound/pcm.h>
200bf750f4SAndy Green #include <sound/pcm_params.h>
210bf750f4SAndy Green #include <sound/dmaengine_pcm.h>
220bf750f4SAndy Green #include <sound/initval.h>
230bf750f4SAndy Green #include <sound/soc.h>
240bf750f4SAndy Green #include <linux/interrupt.h>
250bf750f4SAndy Green #include <linux/reset.h>
260bf750f4SAndy Green #include <linux/of_address.h>
270bf750f4SAndy Green #include <linux/of_irq.h>
280bf750f4SAndy Green #include <linux/mfd/syscon.h>
290bf750f4SAndy Green #include <linux/reset-controller.h>
300bf750f4SAndy Green
310bf750f4SAndy Green #include "hi6210-i2s.h"
320bf750f4SAndy Green
330bf750f4SAndy Green struct hi6210_i2s {
340bf750f4SAndy Green struct device *dev;
350bf750f4SAndy Green struct reset_control *rc;
360bf750f4SAndy Green struct clk *clk[8];
370bf750f4SAndy Green int clocks;
380bf750f4SAndy Green struct snd_soc_dai_driver dai;
390bf750f4SAndy Green void __iomem *base;
400bf750f4SAndy Green struct regmap *sysctrl;
410bf750f4SAndy Green phys_addr_t base_phys;
420bf750f4SAndy Green struct snd_dmaengine_dai_dma_data dma_data[2];
430bf750f4SAndy Green int clk_rate;
440bf750f4SAndy Green spinlock_t lock;
450bf750f4SAndy Green int rate;
460bf750f4SAndy Green int format;
470bf750f4SAndy Green u8 bits;
480bf750f4SAndy Green u8 channels;
490bf750f4SAndy Green u8 id;
500bf750f4SAndy Green u8 channel_length;
510bf750f4SAndy Green u8 use;
520bf750f4SAndy Green u32 master:1;
530bf750f4SAndy Green u32 status:1;
540bf750f4SAndy Green };
550bf750f4SAndy Green
560bf750f4SAndy Green #define SC_PERIPH_CLKEN1 0x210
570bf750f4SAndy Green #define SC_PERIPH_CLKDIS1 0x214
580bf750f4SAndy Green
590bf750f4SAndy Green #define SC_PERIPH_CLKEN3 0x230
600bf750f4SAndy Green #define SC_PERIPH_CLKDIS3 0x234
610bf750f4SAndy Green
620bf750f4SAndy Green #define SC_PERIPH_CLKEN12 0x270
630bf750f4SAndy Green #define SC_PERIPH_CLKDIS12 0x274
640bf750f4SAndy Green
650bf750f4SAndy Green #define SC_PERIPH_RSTEN1 0x310
660bf750f4SAndy Green #define SC_PERIPH_RSTDIS1 0x314
670bf750f4SAndy Green #define SC_PERIPH_RSTSTAT1 0x318
680bf750f4SAndy Green
690bf750f4SAndy Green #define SC_PERIPH_RSTEN2 0x320
700bf750f4SAndy Green #define SC_PERIPH_RSTDIS2 0x324
710bf750f4SAndy Green #define SC_PERIPH_RSTSTAT2 0x328
720bf750f4SAndy Green
730bf750f4SAndy Green #define SOC_PMCTRL_BBPPLLALIAS 0x48
740bf750f4SAndy Green
750bf750f4SAndy Green enum {
760bf750f4SAndy Green CLK_DACODEC,
770bf750f4SAndy Green CLK_I2S_BASE,
780bf750f4SAndy Green };
790bf750f4SAndy Green
hi6210_write_reg(struct hi6210_i2s * i2s,int reg,u32 val)800bf750f4SAndy Green static inline void hi6210_write_reg(struct hi6210_i2s *i2s, int reg, u32 val)
810bf750f4SAndy Green {
820bf750f4SAndy Green writel(val, i2s->base + reg);
830bf750f4SAndy Green }
840bf750f4SAndy Green
hi6210_read_reg(struct hi6210_i2s * i2s,int reg)850bf750f4SAndy Green static inline u32 hi6210_read_reg(struct hi6210_i2s *i2s, int reg)
860bf750f4SAndy Green {
870bf750f4SAndy Green return readl(i2s->base + reg);
880bf750f4SAndy Green }
890bf750f4SAndy Green
hi6210_i2s_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)902a54e845STakashi Sakamoto static int hi6210_i2s_startup(struct snd_pcm_substream *substream,
910bf750f4SAndy Green struct snd_soc_dai *cpu_dai)
920bf750f4SAndy Green {
930bf750f4SAndy Green struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
940bf750f4SAndy Green int ret, n;
950bf750f4SAndy Green u32 val;
960bf750f4SAndy Green
970bf750f4SAndy Green /* deassert reset on ABB */
980bf750f4SAndy Green regmap_read(i2s->sysctrl, SC_PERIPH_RSTSTAT2, &val);
990bf750f4SAndy Green if (val & BIT(4))
1000bf750f4SAndy Green regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS2, BIT(4));
1010bf750f4SAndy Green
1020bf750f4SAndy Green for (n = 0; n < i2s->clocks; n++) {
1030bf750f4SAndy Green ret = clk_prepare_enable(i2s->clk[n]);
104375904e3SYang Yingliang if (ret)
105375904e3SYang Yingliang goto err_unprepare_clk;
1060bf750f4SAndy Green }
1070bf750f4SAndy Green
1080bf750f4SAndy Green ret = clk_set_rate(i2s->clk[CLK_I2S_BASE], 49152000);
1090bf750f4SAndy Green if (ret) {
1100bf750f4SAndy Green dev_err(i2s->dev, "%s: setting 49.152MHz base rate failed %d\n",
1110bf750f4SAndy Green __func__, ret);
112375904e3SYang Yingliang goto err_unprepare_clk;
1130bf750f4SAndy Green }
1140bf750f4SAndy Green
1150bf750f4SAndy Green /* enable clock before frequency division */
1160bf750f4SAndy Green regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN12, BIT(9));
1170bf750f4SAndy Green
1180bf750f4SAndy Green /* enable codec working clock / == "codec bus clock" */
1190bf750f4SAndy Green regmap_write(i2s->sysctrl, SC_PERIPH_CLKEN1, BIT(5));
1200bf750f4SAndy Green
1210bf750f4SAndy Green /* deassert reset on codec / interface clock / working clock */
1220bf750f4SAndy Green regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5));
1230bf750f4SAndy Green regmap_write(i2s->sysctrl, SC_PERIPH_RSTDIS1, BIT(5));
1240bf750f4SAndy Green
1250bf750f4SAndy Green /* not interested in i2s irqs */
1260bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_CODEC_IRQ_MASK);
1270bf750f4SAndy Green val |= 0x3f;
1280bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_CODEC_IRQ_MASK, val);
1290bf750f4SAndy Green
1300bf750f4SAndy Green
1310bf750f4SAndy Green /* reset the stereo downlink fifo */
1320bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1);
1330bf750f4SAndy Green val |= (BIT(5) | BIT(4));
1340bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val);
1350bf750f4SAndy Green
1360bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_APB_AFIFO_CFG_1);
1370bf750f4SAndy Green val &= ~(BIT(5) | BIT(4));
1380bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_APB_AFIFO_CFG_1, val);
1390bf750f4SAndy Green
1400bf750f4SAndy Green
1410bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_SW_RST_N);
1420bf750f4SAndy Green val &= ~(HII2S_SW_RST_N__ST_DL_WORDLEN_MASK <<
1430bf750f4SAndy Green HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT);
1440bf750f4SAndy Green val |= (HII2S_BITS_16 << HII2S_SW_RST_N__ST_DL_WORDLEN_SHIFT);
1450bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_SW_RST_N, val);
1460bf750f4SAndy Green
1470bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_MISC_CFG);
1480bf750f4SAndy Green /* mux 11/12 = APB not i2s */
1490bf750f4SAndy Green val &= ~HII2S_MISC_CFG__ST_DL_TEST_SEL;
1500bf750f4SAndy Green /* BT R ch 0 = mixer op of DACR ch */
1510bf750f4SAndy Green val &= ~HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL;
1520bf750f4SAndy Green val &= ~HII2S_MISC_CFG__S2_DOUT_TEST_SEL;
1530bf750f4SAndy Green
1540bf750f4SAndy Green val |= HII2S_MISC_CFG__S2_DOUT_RIGHT_SEL;
1550bf750f4SAndy Green /* BT L ch = 1 = mux 7 = "mixer output of DACL */
1560bf750f4SAndy Green val |= HII2S_MISC_CFG__S2_DOUT_TEST_SEL;
1570bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_MISC_CFG, val);
1580bf750f4SAndy Green
1590bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_SW_RST_N);
1600bf750f4SAndy Green val |= HII2S_SW_RST_N__SW_RST_N;
1610bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_SW_RST_N, val);
1620bf750f4SAndy Green
1630bf750f4SAndy Green return 0;
164375904e3SYang Yingliang
165375904e3SYang Yingliang err_unprepare_clk:
166375904e3SYang Yingliang while (n--)
167375904e3SYang Yingliang clk_disable_unprepare(i2s->clk[n]);
168375904e3SYang Yingliang return ret;
1690bf750f4SAndy Green }
1702a54e845STakashi Sakamoto
hi6210_i2s_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)1712a54e845STakashi Sakamoto static void hi6210_i2s_shutdown(struct snd_pcm_substream *substream,
1720bf750f4SAndy Green struct snd_soc_dai *cpu_dai)
1730bf750f4SAndy Green {
1740bf750f4SAndy Green struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
1750bf750f4SAndy Green int n;
1760bf750f4SAndy Green
1770bf750f4SAndy Green for (n = 0; n < i2s->clocks; n++)
1780bf750f4SAndy Green clk_disable_unprepare(i2s->clk[n]);
1790bf750f4SAndy Green
1800bf750f4SAndy Green regmap_write(i2s->sysctrl, SC_PERIPH_RSTEN1, BIT(5));
1810bf750f4SAndy Green }
1820bf750f4SAndy Green
hi6210_i2s_txctrl(struct snd_soc_dai * cpu_dai,int on)1830bf750f4SAndy Green static void hi6210_i2s_txctrl(struct snd_soc_dai *cpu_dai, int on)
1840bf750f4SAndy Green {
1850bf750f4SAndy Green struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
1860bf750f4SAndy Green u32 val;
1870bf750f4SAndy Green
1880bf750f4SAndy Green spin_lock(&i2s->lock);
1890bf750f4SAndy Green if (on) {
1900bf750f4SAndy Green /* enable S2 TX */
1910bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
1920bf750f4SAndy Green val |= HII2S_I2S_CFG__S2_IF_TX_EN;
1930bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
1940bf750f4SAndy Green } else {
1950bf750f4SAndy Green /* disable S2 TX */
1960bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
1970bf750f4SAndy Green val &= ~HII2S_I2S_CFG__S2_IF_TX_EN;
1980bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
1990bf750f4SAndy Green }
2000bf750f4SAndy Green spin_unlock(&i2s->lock);
2010bf750f4SAndy Green }
2020bf750f4SAndy Green
hi6210_i2s_rxctrl(struct snd_soc_dai * cpu_dai,int on)2030bf750f4SAndy Green static void hi6210_i2s_rxctrl(struct snd_soc_dai *cpu_dai, int on)
2040bf750f4SAndy Green {
2050bf750f4SAndy Green struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
2060bf750f4SAndy Green u32 val;
2070bf750f4SAndy Green
2080bf750f4SAndy Green spin_lock(&i2s->lock);
2090bf750f4SAndy Green if (on) {
2100bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
2110bf750f4SAndy Green val |= HII2S_I2S_CFG__S2_IF_RX_EN;
2120bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
2130bf750f4SAndy Green } else {
2140bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
2150bf750f4SAndy Green val &= ~HII2S_I2S_CFG__S2_IF_RX_EN;
2160bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
2170bf750f4SAndy Green }
2180bf750f4SAndy Green spin_unlock(&i2s->lock);
2190bf750f4SAndy Green }
2200bf750f4SAndy Green
hi6210_i2s_set_fmt(struct snd_soc_dai * cpu_dai,unsigned int fmt)2210bf750f4SAndy Green static int hi6210_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
2220bf750f4SAndy Green {
2230bf750f4SAndy Green struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
2240bf750f4SAndy Green
2250bf750f4SAndy Green /*
2260bf750f4SAndy Green * We don't actually set the hardware until the hw_params
2270bf750f4SAndy Green * call, but we need to validate the user input here.
2280bf750f4SAndy Green */
2290f362524SCharles Keepax switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
2300f362524SCharles Keepax case SND_SOC_DAIFMT_BC_FC:
2310f362524SCharles Keepax case SND_SOC_DAIFMT_BP_FP:
2320bf750f4SAndy Green break;
2330bf750f4SAndy Green default:
2340bf750f4SAndy Green return -EINVAL;
2350bf750f4SAndy Green }
2360bf750f4SAndy Green
2370bf750f4SAndy Green switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
2380bf750f4SAndy Green case SND_SOC_DAIFMT_I2S:
2390bf750f4SAndy Green case SND_SOC_DAIFMT_LEFT_J:
2400bf750f4SAndy Green case SND_SOC_DAIFMT_RIGHT_J:
2410bf750f4SAndy Green break;
2420bf750f4SAndy Green default:
2430bf750f4SAndy Green return -EINVAL;
2440bf750f4SAndy Green }
2450bf750f4SAndy Green
2460bf750f4SAndy Green i2s->format = fmt;
2470f362524SCharles Keepax i2s->master = (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) ==
2480f362524SCharles Keepax SND_SOC_DAIFMT_BP_FP;
2490bf750f4SAndy Green
2500bf750f4SAndy Green return 0;
2510bf750f4SAndy Green }
2520bf750f4SAndy Green
hi6210_i2s_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * cpu_dai)2530bf750f4SAndy Green static int hi6210_i2s_hw_params(struct snd_pcm_substream *substream,
2540bf750f4SAndy Green struct snd_pcm_hw_params *params,
2550bf750f4SAndy Green struct snd_soc_dai *cpu_dai)
2560bf750f4SAndy Green {
2570bf750f4SAndy Green struct hi6210_i2s *i2s = dev_get_drvdata(cpu_dai->dev);
2580bf750f4SAndy Green u32 bits = 0, rate = 0, signed_data = 0, fmt = 0;
2590bf750f4SAndy Green u32 val;
2600bf750f4SAndy Green struct snd_dmaengine_dai_dma_data *dma_data;
2610bf750f4SAndy Green
2620bf750f4SAndy Green switch (params_format(params)) {
2630bf750f4SAndy Green case SNDRV_PCM_FORMAT_U16_LE:
2640bf750f4SAndy Green signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
265df561f66SGustavo A. R. Silva fallthrough;
2660bf750f4SAndy Green case SNDRV_PCM_FORMAT_S16_LE:
2670bf750f4SAndy Green bits = HII2S_BITS_16;
2680bf750f4SAndy Green break;
2690bf750f4SAndy Green case SNDRV_PCM_FORMAT_U24_LE:
2700bf750f4SAndy Green signed_data = HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
271df561f66SGustavo A. R. Silva fallthrough;
2720bf750f4SAndy Green case SNDRV_PCM_FORMAT_S24_LE:
2730bf750f4SAndy Green bits = HII2S_BITS_24;
2740bf750f4SAndy Green break;
2750bf750f4SAndy Green default:
2760bf750f4SAndy Green dev_err(cpu_dai->dev, "Bad format\n");
2770bf750f4SAndy Green return -EINVAL;
2780bf750f4SAndy Green }
2790bf750f4SAndy Green
2800bf750f4SAndy Green
2810bf750f4SAndy Green switch (params_rate(params)) {
2820bf750f4SAndy Green case 8000:
2830bf750f4SAndy Green rate = HII2S_FS_RATE_8KHZ;
2840bf750f4SAndy Green break;
2850bf750f4SAndy Green case 16000:
2860bf750f4SAndy Green rate = HII2S_FS_RATE_16KHZ;
2870bf750f4SAndy Green break;
2880bf750f4SAndy Green case 32000:
2890bf750f4SAndy Green rate = HII2S_FS_RATE_32KHZ;
2900bf750f4SAndy Green break;
2910bf750f4SAndy Green case 48000:
2920bf750f4SAndy Green rate = HII2S_FS_RATE_48KHZ;
2930bf750f4SAndy Green break;
2940bf750f4SAndy Green case 96000:
2950bf750f4SAndy Green rate = HII2S_FS_RATE_96KHZ;
2960bf750f4SAndy Green break;
2970bf750f4SAndy Green case 192000:
2980bf750f4SAndy Green rate = HII2S_FS_RATE_192KHZ;
2990bf750f4SAndy Green break;
3000bf750f4SAndy Green default:
3010bf750f4SAndy Green dev_err(cpu_dai->dev, "Bad rate: %d\n", params_rate(params));
3020bf750f4SAndy Green return -EINVAL;
3030bf750f4SAndy Green }
3040bf750f4SAndy Green
3050bf750f4SAndy Green if (!(params_channels(params))) {
3060bf750f4SAndy Green dev_err(cpu_dai->dev, "Bad channels\n");
3070bf750f4SAndy Green return -EINVAL;
3080bf750f4SAndy Green }
3090bf750f4SAndy Green
3100bf750f4SAndy Green dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
3110bf750f4SAndy Green
3120bf750f4SAndy Green switch (bits) {
3130bf750f4SAndy Green case HII2S_BITS_24:
3140bf750f4SAndy Green i2s->bits = 32;
3150bf750f4SAndy Green dma_data->addr_width = 3;
3160bf750f4SAndy Green break;
3170bf750f4SAndy Green default:
3180bf750f4SAndy Green i2s->bits = 16;
3190bf750f4SAndy Green dma_data->addr_width = 2;
32016c1c089SJohn Stultz break;
3210bf750f4SAndy Green }
3220bf750f4SAndy Green i2s->rate = params_rate(params);
3230bf750f4SAndy Green i2s->channels = params_channels(params);
3240bf750f4SAndy Green i2s->channel_length = i2s->channels * i2s->bits;
3250bf750f4SAndy Green
3260bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG);
3270bf750f4SAndy Green val &= ~((HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_MASK <<
3280bf750f4SAndy Green HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) |
3290bf750f4SAndy Green (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_MASK <<
3300bf750f4SAndy Green HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) |
3310bf750f4SAndy Green (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_MASK <<
3320bf750f4SAndy Green HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) |
3330bf750f4SAndy Green (HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_MASK <<
3340bf750f4SAndy Green HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT));
3350bf750f4SAndy Green val |= ((16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AEMPTY_SHIFT) |
3360bf750f4SAndy Green (30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_R_AFULL_SHIFT) |
3370bf750f4SAndy Green (16 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AEMPTY_SHIFT) |
3380bf750f4SAndy Green (30 << HII2S_ST_DL_FIFO_TH_CFG__ST_DL_L_AFULL_SHIFT));
3390bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_ST_DL_FIFO_TH_CFG, val);
3400bf750f4SAndy Green
3410bf750f4SAndy Green
3420bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_IF_CLK_EN_CFG);
3430bf750f4SAndy Green val |= (BIT(19) | BIT(18) | BIT(17) |
3440bf750f4SAndy Green HII2S_IF_CLK_EN_CFG__S2_IF_CLK_EN |
3450bf750f4SAndy Green HII2S_IF_CLK_EN_CFG__S2_OL_MIXER_EN |
3460bf750f4SAndy Green HII2S_IF_CLK_EN_CFG__S2_OL_SRC_EN |
3470bf750f4SAndy Green HII2S_IF_CLK_EN_CFG__ST_DL_R_EN |
3480bf750f4SAndy Green HII2S_IF_CLK_EN_CFG__ST_DL_L_EN);
3490bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_IF_CLK_EN_CFG, val);
3500bf750f4SAndy Green
3510bf750f4SAndy Green
3520bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG);
3530bf750f4SAndy Green val &= ~(HII2S_DIG_FILTER_CLK_EN_CFG__DACR_SDM_EN |
3540bf750f4SAndy Green HII2S_DIG_FILTER_CLK_EN_CFG__DACR_HBF2I_EN |
3550bf750f4SAndy Green HII2S_DIG_FILTER_CLK_EN_CFG__DACR_AGC_EN |
3560bf750f4SAndy Green HII2S_DIG_FILTER_CLK_EN_CFG__DACL_SDM_EN |
3570bf750f4SAndy Green HII2S_DIG_FILTER_CLK_EN_CFG__DACL_HBF2I_EN |
3580bf750f4SAndy Green HII2S_DIG_FILTER_CLK_EN_CFG__DACL_AGC_EN);
3590bf750f4SAndy Green val |= (HII2S_DIG_FILTER_CLK_EN_CFG__DACR_MIXER_EN |
3600bf750f4SAndy Green HII2S_DIG_FILTER_CLK_EN_CFG__DACL_MIXER_EN);
3610bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_DIG_FILTER_CLK_EN_CFG, val);
3620bf750f4SAndy Green
3630bf750f4SAndy Green
3640bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG);
3650bf750f4SAndy Green val &= ~(HII2S_DIG_FILTER_MODULE_CFG__DACR_MIXER_IN2_MUTE |
3660bf750f4SAndy Green HII2S_DIG_FILTER_MODULE_CFG__DACL_MIXER_IN2_MUTE);
3670bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_DIG_FILTER_MODULE_CFG, val);
3680bf750f4SAndy Green
3690bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_MUX_TOP_MODULE_CFG);
3700bf750f4SAndy Green val &= ~(HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN1_MUTE |
3710bf750f4SAndy Green HII2S_MUX_TOP_MODULE_CFG__S2_OL_MIXER_IN2_MUTE |
3720bf750f4SAndy Green HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN1_MUTE |
3730bf750f4SAndy Green HII2S_MUX_TOP_MODULE_CFG__VOICE_DLINK_MIXER_IN2_MUTE);
3740bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_MUX_TOP_MODULE_CFG, val);
3750bf750f4SAndy Green
3760bf750f4SAndy Green
3770f362524SCharles Keepax switch (i2s->format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
3780f362524SCharles Keepax case SND_SOC_DAIFMT_BC_FC:
3790bf750f4SAndy Green i2s->master = false;
3800bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
3810bf750f4SAndy Green val |= HII2S_I2S_CFG__S2_MST_SLV;
3820bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
3830bf750f4SAndy Green break;
3840f362524SCharles Keepax case SND_SOC_DAIFMT_BP_FP:
3850bf750f4SAndy Green i2s->master = true;
3860bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
3870bf750f4SAndy Green val &= ~HII2S_I2S_CFG__S2_MST_SLV;
3880bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
3890bf750f4SAndy Green break;
3900bf750f4SAndy Green default:
3910f362524SCharles Keepax WARN_ONCE(1, "Invalid i2s->fmt CLOCK_PROVIDER_MASK. This shouldn't happen\n");
392da13d746SJohn Stultz return -EINVAL;
3930bf750f4SAndy Green }
3940bf750f4SAndy Green
3950bf750f4SAndy Green switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
3960bf750f4SAndy Green case SND_SOC_DAIFMT_I2S:
3970bf750f4SAndy Green fmt = HII2S_FORMAT_I2S;
3980bf750f4SAndy Green break;
3990bf750f4SAndy Green case SND_SOC_DAIFMT_LEFT_J:
4000bf750f4SAndy Green fmt = HII2S_FORMAT_LEFT_JUST;
4010bf750f4SAndy Green break;
4020bf750f4SAndy Green case SND_SOC_DAIFMT_RIGHT_J:
4030bf750f4SAndy Green fmt = HII2S_FORMAT_RIGHT_JUST;
4040bf750f4SAndy Green break;
4050bf750f4SAndy Green default:
4060bf750f4SAndy Green WARN_ONCE(1, "Invalid i2s->fmt FORMAT_MASK. This shouldn't happen\n");
407da13d746SJohn Stultz return -EINVAL;
4080bf750f4SAndy Green }
4090bf750f4SAndy Green
4100bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4110bf750f4SAndy Green val &= ~(HII2S_I2S_CFG__S2_FUNC_MODE_MASK <<
4120bf750f4SAndy Green HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT);
4130bf750f4SAndy Green val |= fmt << HII2S_I2S_CFG__S2_FUNC_MODE_SHIFT;
4140bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4150bf750f4SAndy Green
4160bf750f4SAndy Green
4170bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_CLK_SEL);
4180bf750f4SAndy Green val &= ~(HII2S_CLK_SEL__I2S_BT_FM_SEL | /* BT gets the I2S */
4190bf750f4SAndy Green HII2S_CLK_SEL__EXT_12_288MHZ_SEL);
4200bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_CLK_SEL, val);
4210bf750f4SAndy Green
4220bf750f4SAndy Green dma_data->maxburst = 2;
4230bf750f4SAndy Green
4240bf750f4SAndy Green if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
4250bf750f4SAndy Green dma_data->addr = i2s->base_phys + HII2S_ST_DL_CHANNEL;
4260bf750f4SAndy Green else
4270bf750f4SAndy Green dma_data->addr = i2s->base_phys + HII2S_STEREO_UPLINK_CHANNEL;
4280bf750f4SAndy Green
4290bf750f4SAndy Green switch (i2s->channels) {
4300bf750f4SAndy Green case 1:
4310bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4320bf750f4SAndy Green val |= HII2S_I2S_CFG__S2_FRAME_MODE;
4330bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4340bf750f4SAndy Green break;
4350bf750f4SAndy Green default:
4360bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4370bf750f4SAndy Green val &= ~HII2S_I2S_CFG__S2_FRAME_MODE;
4380bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
43916c1c089SJohn Stultz break;
4400bf750f4SAndy Green }
4410bf750f4SAndy Green
4420bf750f4SAndy Green /* clear loopback, set signed type and word length */
4430bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_I2S_CFG);
4440bf750f4SAndy Green val &= ~HII2S_I2S_CFG__S2_CODEC_DATA_FORMAT;
4450bf750f4SAndy Green val &= ~(HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_MASK <<
4460bf750f4SAndy Green HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT);
4470bf750f4SAndy Green val &= ~(HII2S_I2S_CFG__S2_DIRECT_LOOP_MASK <<
4480bf750f4SAndy Green HII2S_I2S_CFG__S2_DIRECT_LOOP_SHIFT);
4490bf750f4SAndy Green val |= signed_data;
4500bf750f4SAndy Green val |= (bits << HII2S_I2S_CFG__S2_CODEC_IO_WORDLENGTH_SHIFT);
4510bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_I2S_CFG, val);
4520bf750f4SAndy Green
4530bf750f4SAndy Green
4540bf750f4SAndy Green if (!i2s->master)
4550bf750f4SAndy Green return 0;
4560bf750f4SAndy Green
4570bf750f4SAndy Green /* set DAC and related units to correct rate */
4580bf750f4SAndy Green val = hi6210_read_reg(i2s, HII2S_FS_CFG);
4590bf750f4SAndy Green val &= ~(HII2S_FS_CFG__FS_S2_MASK << HII2S_FS_CFG__FS_S2_SHIFT);
4600bf750f4SAndy Green val &= ~(HII2S_FS_CFG__FS_DACLR_MASK << HII2S_FS_CFG__FS_DACLR_SHIFT);
4610bf750f4SAndy Green val &= ~(HII2S_FS_CFG__FS_ST_DL_R_MASK <<
4620bf750f4SAndy Green HII2S_FS_CFG__FS_ST_DL_R_SHIFT);
4630bf750f4SAndy Green val &= ~(HII2S_FS_CFG__FS_ST_DL_L_MASK <<
4640bf750f4SAndy Green HII2S_FS_CFG__FS_ST_DL_L_SHIFT);
4650bf750f4SAndy Green val |= (rate << HII2S_FS_CFG__FS_S2_SHIFT);
4660bf750f4SAndy Green val |= (rate << HII2S_FS_CFG__FS_DACLR_SHIFT);
4670bf750f4SAndy Green val |= (rate << HII2S_FS_CFG__FS_ST_DL_R_SHIFT);
4680bf750f4SAndy Green val |= (rate << HII2S_FS_CFG__FS_ST_DL_L_SHIFT);
4690bf750f4SAndy Green hi6210_write_reg(i2s, HII2S_FS_CFG, val);
4700bf750f4SAndy Green
4710bf750f4SAndy Green return 0;
4720bf750f4SAndy Green }
4730bf750f4SAndy Green
hi6210_i2s_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * cpu_dai)4740bf750f4SAndy Green static int hi6210_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
4750bf750f4SAndy Green struct snd_soc_dai *cpu_dai)
4760bf750f4SAndy Green {
4770bf750f4SAndy Green pr_debug("%s\n", __func__);
4780bf750f4SAndy Green switch (cmd) {
4790bf750f4SAndy Green case SNDRV_PCM_TRIGGER_START:
4800bf750f4SAndy Green case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
4810bf750f4SAndy Green if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
4820bf750f4SAndy Green hi6210_i2s_rxctrl(cpu_dai, 1);
4830bf750f4SAndy Green else
4840bf750f4SAndy Green hi6210_i2s_txctrl(cpu_dai, 1);
4850bf750f4SAndy Green break;
4860bf750f4SAndy Green case SNDRV_PCM_TRIGGER_STOP:
4870bf750f4SAndy Green case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4880bf750f4SAndy Green if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
4890bf750f4SAndy Green hi6210_i2s_rxctrl(cpu_dai, 0);
4900bf750f4SAndy Green else
4910bf750f4SAndy Green hi6210_i2s_txctrl(cpu_dai, 0);
4920bf750f4SAndy Green break;
4930bf750f4SAndy Green default:
4942b8eae79SColin Ian King dev_err(cpu_dai->dev, "unknown cmd\n");
4950bf750f4SAndy Green return -EINVAL;
4960bf750f4SAndy Green }
4970bf750f4SAndy Green return 0;
4980bf750f4SAndy Green }
4990bf750f4SAndy Green
hi6210_i2s_dai_probe(struct snd_soc_dai * dai)5000bf750f4SAndy Green static int hi6210_i2s_dai_probe(struct snd_soc_dai *dai)
5010bf750f4SAndy Green {
5020bf750f4SAndy Green struct hi6210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
5030bf750f4SAndy Green
5040bf750f4SAndy Green snd_soc_dai_init_dma_data(dai,
5050bf750f4SAndy Green &i2s->dma_data[SNDRV_PCM_STREAM_PLAYBACK],
5060bf750f4SAndy Green &i2s->dma_data[SNDRV_PCM_STREAM_CAPTURE]);
5070bf750f4SAndy Green
5080bf750f4SAndy Green return 0;
5090bf750f4SAndy Green }
5100bf750f4SAndy Green
5110bf750f4SAndy Green
51294372fceSGustavo A. R. Silva static const struct snd_soc_dai_ops hi6210_i2s_dai_ops = {
513*4f1ec3daSKuninori Morimoto .probe = hi6210_i2s_dai_probe,
5140bf750f4SAndy Green .trigger = hi6210_i2s_trigger,
5150bf750f4SAndy Green .hw_params = hi6210_i2s_hw_params,
516b9a79728SCharles Keepax .set_fmt = hi6210_i2s_set_fmt,
5170bf750f4SAndy Green .startup = hi6210_i2s_startup,
5180bf750f4SAndy Green .shutdown = hi6210_i2s_shutdown,
5190bf750f4SAndy Green };
5200bf750f4SAndy Green
5212a54e845STakashi Sakamoto static const struct snd_soc_dai_driver hi6210_i2s_dai_init = {
5220bf750f4SAndy Green .playback = {
5230bf750f4SAndy Green .channels_min = 2,
5240bf750f4SAndy Green .channels_max = 2,
5250bf750f4SAndy Green .formats = SNDRV_PCM_FMTBIT_S16_LE |
5260bf750f4SAndy Green SNDRV_PCM_FMTBIT_U16_LE,
5270bf750f4SAndy Green .rates = SNDRV_PCM_RATE_48000,
5280bf750f4SAndy Green },
5290bf750f4SAndy Green .capture = {
5300bf750f4SAndy Green .channels_min = 2,
5310bf750f4SAndy Green .channels_max = 2,
5320bf750f4SAndy Green .formats = SNDRV_PCM_FMTBIT_S16_LE |
5330bf750f4SAndy Green SNDRV_PCM_FMTBIT_U16_LE,
5340bf750f4SAndy Green .rates = SNDRV_PCM_RATE_48000,
5350bf750f4SAndy Green },
5360bf750f4SAndy Green .ops = &hi6210_i2s_dai_ops,
5370bf750f4SAndy Green };
5380bf750f4SAndy Green
5390bf750f4SAndy Green static const struct snd_soc_component_driver hi6210_i2s_i2s_comp = {
5400bf750f4SAndy Green .name = "hi6210_i2s-i2s",
541bf6dacb7SCharles Keepax .legacy_dai_naming = 1,
5420bf750f4SAndy Green };
5430bf750f4SAndy Green
hi6210_i2s_probe(struct platform_device * pdev)5440bf750f4SAndy Green static int hi6210_i2s_probe(struct platform_device *pdev)
5450bf750f4SAndy Green {
5460bf750f4SAndy Green struct device_node *node = pdev->dev.of_node;
5470bf750f4SAndy Green struct device *dev = &pdev->dev;
5480bf750f4SAndy Green struct hi6210_i2s *i2s;
5490bf750f4SAndy Green struct resource *res;
5500bf750f4SAndy Green int ret;
5510bf750f4SAndy Green
55277060f4fSTang Bin i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
5530bf750f4SAndy Green if (!i2s)
5540bf750f4SAndy Green return -ENOMEM;
5550bf750f4SAndy Green
5560bf750f4SAndy Green i2s->dev = dev;
5570bf750f4SAndy Green spin_lock_init(&i2s->lock);
5580bf750f4SAndy Green
559afc3a0b4SYang Yingliang i2s->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
5600bf750f4SAndy Green if (IS_ERR(i2s->base))
5610bf750f4SAndy Green return PTR_ERR(i2s->base);
5620bf750f4SAndy Green
5630bf750f4SAndy Green i2s->base_phys = (phys_addr_t)res->start;
5640bf750f4SAndy Green i2s->dai = hi6210_i2s_dai_init;
5650bf750f4SAndy Green
56677060f4fSTang Bin dev_set_drvdata(dev, i2s);
5670bf750f4SAndy Green
5680bf750f4SAndy Green i2s->sysctrl = syscon_regmap_lookup_by_phandle(node,
5690bf750f4SAndy Green "hisilicon,sysctrl-syscon");
5700bf750f4SAndy Green if (IS_ERR(i2s->sysctrl))
5710bf750f4SAndy Green return PTR_ERR(i2s->sysctrl);
5720bf750f4SAndy Green
57377060f4fSTang Bin i2s->clk[CLK_DACODEC] = devm_clk_get(dev, "dacodec");
574e782ddbbSTang Bin if (IS_ERR(i2s->clk[CLK_DACODEC]))
5750bf750f4SAndy Green return PTR_ERR(i2s->clk[CLK_DACODEC]);
5760bf750f4SAndy Green i2s->clocks++;
5770bf750f4SAndy Green
57877060f4fSTang Bin i2s->clk[CLK_I2S_BASE] = devm_clk_get(dev, "i2s-base");
579e782ddbbSTang Bin if (IS_ERR(i2s->clk[CLK_I2S_BASE]))
5800bf750f4SAndy Green return PTR_ERR(i2s->clk[CLK_I2S_BASE]);
5810bf750f4SAndy Green i2s->clocks++;
5820bf750f4SAndy Green
58377060f4fSTang Bin ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0);
5840bf750f4SAndy Green if (ret)
5850bf750f4SAndy Green return ret;
5860bf750f4SAndy Green
58777060f4fSTang Bin ret = devm_snd_soc_register_component(dev, &hi6210_i2s_i2s_comp,
5880bf750f4SAndy Green &i2s->dai, 1);
5890bf750f4SAndy Green return ret;
5900bf750f4SAndy Green }
5910bf750f4SAndy Green
5920bf750f4SAndy Green static const struct of_device_id hi6210_i2s_dt_ids[] = {
5930bf750f4SAndy Green { .compatible = "hisilicon,hi6210-i2s" },
5940bf750f4SAndy Green { /* sentinel */ }
5950bf750f4SAndy Green };
5960bf750f4SAndy Green
5970bf750f4SAndy Green MODULE_DEVICE_TABLE(of, hi6210_i2s_dt_ids);
5980bf750f4SAndy Green
5990bf750f4SAndy Green static struct platform_driver hi6210_i2s_driver = {
6000bf750f4SAndy Green .probe = hi6210_i2s_probe,
6010bf750f4SAndy Green .driver = {
6020bf750f4SAndy Green .name = "hi6210_i2s",
6030bf750f4SAndy Green .of_match_table = hi6210_i2s_dt_ids,
6040bf750f4SAndy Green },
6050bf750f4SAndy Green };
6060bf750f4SAndy Green
6070bf750f4SAndy Green module_platform_driver(hi6210_i2s_driver);
6080bf750f4SAndy Green
6090bf750f4SAndy Green MODULE_DESCRIPTION("Hisilicon HI6210 I2S driver");
6100bf750f4SAndy Green MODULE_AUTHOR("Andy Green <andy.green@linaro.org>");
6110bf750f4SAndy Green MODULE_LICENSE("GPL");
612