18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/init.h>
78c2ecf20Sopenharmony_ci#include <linux/io.h>
88c2ecf20Sopenharmony_ci#include <linux/of.h>
98c2ecf20Sopenharmony_ci#include <linux/of_device.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/clk.h>
168c2ecf20Sopenharmony_ci#include <linux/delay.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <sound/core.h>
218c2ecf20Sopenharmony_ci#include <sound/pcm.h>
228c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
238c2ecf20Sopenharmony_ci#include <sound/soc.h>
248c2ecf20Sopenharmony_ci#include <sound/initval.h>
258c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include "jz4740-i2s.h"
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define JZ4740_DMA_TYPE_AIC_TRANSMIT 24
308c2ecf20Sopenharmony_ci#define JZ4740_DMA_TYPE_AIC_RECEIVE 25
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define JZ_REG_AIC_CONF		0x00
338c2ecf20Sopenharmony_ci#define JZ_REG_AIC_CTRL		0x04
348c2ecf20Sopenharmony_ci#define JZ_REG_AIC_I2S_FMT	0x10
358c2ecf20Sopenharmony_ci#define JZ_REG_AIC_FIFO_STATUS	0x14
368c2ecf20Sopenharmony_ci#define JZ_REG_AIC_I2S_STATUS	0x1c
378c2ecf20Sopenharmony_ci#define JZ_REG_AIC_CLK_DIV	0x30
388c2ecf20Sopenharmony_ci#define JZ_REG_AIC_FIFO		0x34
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_MASK (0xf << 12)
418c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_MASK (0xf <<  8)
428c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_OVERFLOW_PLAY_LAST BIT(6)
438c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_INTERNAL_CODEC BIT(5)
448c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_I2S BIT(4)
458c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_RESET BIT(3)
468c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_BIT_CLK_MASTER BIT(2)
478c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_SYNC_CLK_MASTER BIT(1)
488c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_ENABLE BIT(0)
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 12
518c2ecf20Sopenharmony_ci#define JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 8
528c2ecf20Sopenharmony_ci#define JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET 24
538c2ecf20Sopenharmony_ci#define JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET 16
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK (0x7 << 19)
568c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK (0x7 << 16)
578c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_ENABLE_RX_DMA BIT(15)
588c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_ENABLE_TX_DMA BIT(14)
598c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_MONO_TO_STEREO BIT(11)
608c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_SWITCH_ENDIANNESS BIT(10)
618c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_SIGNED_TO_UNSIGNED BIT(9)
628c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_TFLUSH		BIT(8)
638c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_RFLUSH		BIT(7)
648c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_ENABLE_ROR_INT BIT(6)
658c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_ENABLE_TUR_INT BIT(5)
668c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_ENABLE_RFS_INT BIT(4)
678c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_ENABLE_TFS_INT BIT(3)
688c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_ENABLE_LOOPBACK BIT(2)
698c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_ENABLE_PLAYBACK BIT(1)
708c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_ENABLE_CAPTURE BIT(0)
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET 19
738c2ecf20Sopenharmony_ci#define JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET  16
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define JZ_AIC_I2S_FMT_DISABLE_BIT_CLK BIT(12)
768c2ecf20Sopenharmony_ci#define JZ_AIC_I2S_FMT_DISABLE_BIT_ICLK BIT(13)
778c2ecf20Sopenharmony_ci#define JZ_AIC_I2S_FMT_ENABLE_SYS_CLK BIT(4)
788c2ecf20Sopenharmony_ci#define JZ_AIC_I2S_FMT_MSB BIT(0)
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci#define JZ_AIC_I2S_STATUS_BUSY BIT(2)
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#define JZ_AIC_CLK_DIV_MASK 0xf
838c2ecf20Sopenharmony_ci#define I2SDIV_DV_SHIFT 0
848c2ecf20Sopenharmony_ci#define I2SDIV_DV_MASK (0xf << I2SDIV_DV_SHIFT)
858c2ecf20Sopenharmony_ci#define I2SDIV_IDV_SHIFT 8
868c2ecf20Sopenharmony_ci#define I2SDIV_IDV_MASK (0xf << I2SDIV_IDV_SHIFT)
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cienum jz47xx_i2s_version {
898c2ecf20Sopenharmony_ci	JZ_I2S_JZ4740,
908c2ecf20Sopenharmony_ci	JZ_I2S_JZ4760,
918c2ecf20Sopenharmony_ci	JZ_I2S_JZ4770,
928c2ecf20Sopenharmony_ci	JZ_I2S_JZ4780,
938c2ecf20Sopenharmony_ci};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistruct i2s_soc_info {
968c2ecf20Sopenharmony_ci	enum jz47xx_i2s_version version;
978c2ecf20Sopenharmony_ci	struct snd_soc_dai_driver *dai;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	bool shared_fifo_flush;
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistruct jz4740_i2s {
1038c2ecf20Sopenharmony_ci	struct resource *mem;
1048c2ecf20Sopenharmony_ci	void __iomem *base;
1058c2ecf20Sopenharmony_ci	dma_addr_t phys_base;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	struct clk *clk_aic;
1088c2ecf20Sopenharmony_ci	struct clk *clk_i2s;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	struct snd_dmaengine_dai_dma_data playback_dma_data;
1118c2ecf20Sopenharmony_ci	struct snd_dmaengine_dai_dma_data capture_dma_data;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	const struct i2s_soc_info *soc_info;
1148c2ecf20Sopenharmony_ci};
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s,
1178c2ecf20Sopenharmony_ci	unsigned int reg)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	return readl(i2s->base + reg);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic inline void jz4740_i2s_write(const struct jz4740_i2s *i2s,
1238c2ecf20Sopenharmony_ci	unsigned int reg, uint32_t value)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	writel(value, i2s->base + reg);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic inline void jz4740_i2s_set_bits(const struct jz4740_i2s *i2s,
1298c2ecf20Sopenharmony_ci	unsigned int reg, uint32_t bits)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	uint32_t value = jz4740_i2s_read(i2s, reg);
1328c2ecf20Sopenharmony_ci	value |= bits;
1338c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, reg, value);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic int jz4740_i2s_startup(struct snd_pcm_substream *substream,
1378c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
1408c2ecf20Sopenharmony_ci	uint32_t conf;
1418c2ecf20Sopenharmony_ci	int ret;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/*
1448c2ecf20Sopenharmony_ci	 * When we can flush FIFOs independently, only flush the FIFO
1458c2ecf20Sopenharmony_ci	 * that is starting up. We can do this when the DAI is active
1468c2ecf20Sopenharmony_ci	 * because it does not disturb other active substreams.
1478c2ecf20Sopenharmony_ci	 */
1488c2ecf20Sopenharmony_ci	if (!i2s->soc_info->shared_fifo_flush) {
1498c2ecf20Sopenharmony_ci		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1508c2ecf20Sopenharmony_ci			jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH);
1518c2ecf20Sopenharmony_ci		else
1528c2ecf20Sopenharmony_ci			jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_RFLUSH);
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	if (snd_soc_dai_active(dai))
1568c2ecf20Sopenharmony_ci		return 0;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/*
1598c2ecf20Sopenharmony_ci	 * When there is a shared flush bit for both FIFOs, the TFLUSH
1608c2ecf20Sopenharmony_ci	 * bit flushes both FIFOs. Flushing while the DAI is active would
1618c2ecf20Sopenharmony_ci	 * cause FIFO underruns in other active substreams so we have to
1628c2ecf20Sopenharmony_ci	 * guard this behind the snd_soc_dai_active() check.
1638c2ecf20Sopenharmony_ci	 */
1648c2ecf20Sopenharmony_ci	if (i2s->soc_info->shared_fifo_flush)
1658c2ecf20Sopenharmony_ci		jz4740_i2s_set_bits(i2s, JZ_REG_AIC_CTRL, JZ_AIC_CTRL_TFLUSH);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(i2s->clk_i2s);
1688c2ecf20Sopenharmony_ci	if (ret)
1698c2ecf20Sopenharmony_ci		return ret;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
1728c2ecf20Sopenharmony_ci	conf |= JZ_AIC_CONF_ENABLE;
1738c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return 0;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
1798c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
1828c2ecf20Sopenharmony_ci	uint32_t conf;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (snd_soc_dai_active(dai))
1858c2ecf20Sopenharmony_ci		return;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
1888c2ecf20Sopenharmony_ci	conf &= ~JZ_AIC_CONF_ENABLE;
1898c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	clk_disable_unprepare(i2s->clk_i2s);
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
1958c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	uint32_t ctrl;
2008c2ecf20Sopenharmony_ci	uint32_t mask;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2038c2ecf20Sopenharmony_ci		mask = JZ_AIC_CTRL_ENABLE_PLAYBACK | JZ_AIC_CTRL_ENABLE_TX_DMA;
2048c2ecf20Sopenharmony_ci	else
2058c2ecf20Sopenharmony_ci		mask = JZ_AIC_CTRL_ENABLE_CAPTURE | JZ_AIC_CTRL_ENABLE_RX_DMA;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	switch (cmd) {
2108c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
2118c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_RESUME:
2128c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2138c2ecf20Sopenharmony_ci		ctrl |= mask;
2148c2ecf20Sopenharmony_ci		break;
2158c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
2168c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_SUSPEND:
2178c2ecf20Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2188c2ecf20Sopenharmony_ci		ctrl &= ~mask;
2198c2ecf20Sopenharmony_ci		break;
2208c2ecf20Sopenharmony_ci	default:
2218c2ecf20Sopenharmony_ci		return -EINVAL;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	return 0;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic int jz4740_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	uint32_t format = 0;
2348c2ecf20Sopenharmony_ci	uint32_t conf;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	conf &= ~(JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2418c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFS:
2428c2ecf20Sopenharmony_ci		conf |= JZ_AIC_CONF_BIT_CLK_MASTER | JZ_AIC_CONF_SYNC_CLK_MASTER;
2438c2ecf20Sopenharmony_ci		format |= JZ_AIC_I2S_FMT_ENABLE_SYS_CLK;
2448c2ecf20Sopenharmony_ci		break;
2458c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFS:
2468c2ecf20Sopenharmony_ci		conf |= JZ_AIC_CONF_SYNC_CLK_MASTER;
2478c2ecf20Sopenharmony_ci		break;
2488c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBS_CFM:
2498c2ecf20Sopenharmony_ci		conf |= JZ_AIC_CONF_BIT_CLK_MASTER;
2508c2ecf20Sopenharmony_ci		break;
2518c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_CBM_CFM:
2528c2ecf20Sopenharmony_ci		break;
2538c2ecf20Sopenharmony_ci	default:
2548c2ecf20Sopenharmony_ci		return -EINVAL;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
2588c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_MSB:
2598c2ecf20Sopenharmony_ci		format |= JZ_AIC_I2S_FMT_MSB;
2608c2ecf20Sopenharmony_ci		break;
2618c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_I2S:
2628c2ecf20Sopenharmony_ci		break;
2638c2ecf20Sopenharmony_ci	default:
2648c2ecf20Sopenharmony_ci		return -EINVAL;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
2688c2ecf20Sopenharmony_ci	case SND_SOC_DAIFMT_NB_NF:
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci	default:
2718c2ecf20Sopenharmony_ci		return -EINVAL;
2728c2ecf20Sopenharmony_ci	}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
2758c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, JZ_REG_AIC_I2S_FMT, format);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	return 0;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic int jz4740_i2s_hw_params(struct snd_pcm_substream *substream,
2818c2ecf20Sopenharmony_ci	struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
2848c2ecf20Sopenharmony_ci	unsigned int sample_size;
2858c2ecf20Sopenharmony_ci	uint32_t ctrl, div_reg;
2868c2ecf20Sopenharmony_ci	int div;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	ctrl = jz4740_i2s_read(i2s, JZ_REG_AIC_CTRL);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	div_reg = jz4740_i2s_read(i2s, JZ_REG_AIC_CLK_DIV);
2918c2ecf20Sopenharmony_ci	div = clk_get_rate(i2s->clk_i2s) / (64 * params_rate(params));
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	switch (params_format(params)) {
2948c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S8:
2958c2ecf20Sopenharmony_ci		sample_size = 0;
2968c2ecf20Sopenharmony_ci		break;
2978c2ecf20Sopenharmony_ci	case SNDRV_PCM_FORMAT_S16:
2988c2ecf20Sopenharmony_ci		sample_size = 1;
2998c2ecf20Sopenharmony_ci		break;
3008c2ecf20Sopenharmony_ci	default:
3018c2ecf20Sopenharmony_ci		return -EINVAL;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
3058c2ecf20Sopenharmony_ci		ctrl &= ~JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_MASK;
3068c2ecf20Sopenharmony_ci		ctrl |= sample_size << JZ_AIC_CTRL_OUTPUT_SAMPLE_SIZE_OFFSET;
3078c2ecf20Sopenharmony_ci		if (params_channels(params) == 1)
3088c2ecf20Sopenharmony_ci			ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO;
3098c2ecf20Sopenharmony_ci		else
3108c2ecf20Sopenharmony_ci			ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci		div_reg &= ~I2SDIV_DV_MASK;
3138c2ecf20Sopenharmony_ci		div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
3148c2ecf20Sopenharmony_ci	} else {
3158c2ecf20Sopenharmony_ci		ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK;
3168c2ecf20Sopenharmony_ci		ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci		if (i2s->soc_info->version >= JZ_I2S_JZ4770) {
3198c2ecf20Sopenharmony_ci			div_reg &= ~I2SDIV_IDV_MASK;
3208c2ecf20Sopenharmony_ci			div_reg |= (div - 1) << I2SDIV_IDV_SHIFT;
3218c2ecf20Sopenharmony_ci		} else {
3228c2ecf20Sopenharmony_ci			div_reg &= ~I2SDIV_DV_MASK;
3238c2ecf20Sopenharmony_ci			div_reg |= (div - 1) << I2SDIV_DV_SHIFT;
3248c2ecf20Sopenharmony_ci		}
3258c2ecf20Sopenharmony_ci	}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl);
3288c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, JZ_REG_AIC_CLK_DIV, div_reg);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	return 0;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic int jz4740_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
3348c2ecf20Sopenharmony_ci	unsigned int freq, int dir)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
3378c2ecf20Sopenharmony_ci	struct clk *parent;
3388c2ecf20Sopenharmony_ci	int ret = 0;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	switch (clk_id) {
3418c2ecf20Sopenharmony_ci	case JZ4740_I2S_CLKSRC_EXT:
3428c2ecf20Sopenharmony_ci		parent = clk_get(NULL, "ext");
3438c2ecf20Sopenharmony_ci		if (IS_ERR(parent))
3448c2ecf20Sopenharmony_ci			return PTR_ERR(parent);
3458c2ecf20Sopenharmony_ci		clk_set_parent(i2s->clk_i2s, parent);
3468c2ecf20Sopenharmony_ci		break;
3478c2ecf20Sopenharmony_ci	case JZ4740_I2S_CLKSRC_PLL:
3488c2ecf20Sopenharmony_ci		parent = clk_get(NULL, "pll half");
3498c2ecf20Sopenharmony_ci		if (IS_ERR(parent))
3508c2ecf20Sopenharmony_ci			return PTR_ERR(parent);
3518c2ecf20Sopenharmony_ci		clk_set_parent(i2s->clk_i2s, parent);
3528c2ecf20Sopenharmony_ci		ret = clk_set_rate(i2s->clk_i2s, freq);
3538c2ecf20Sopenharmony_ci		break;
3548c2ecf20Sopenharmony_ci	default:
3558c2ecf20Sopenharmony_ci		return -EINVAL;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci	clk_put(parent);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	return ret;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic int jz4740_i2s_suspend(struct snd_soc_component *component)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
3658c2ecf20Sopenharmony_ci	uint32_t conf;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	if (snd_soc_component_active(component)) {
3688c2ecf20Sopenharmony_ci		conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
3698c2ecf20Sopenharmony_ci		conf &= ~JZ_AIC_CONF_ENABLE;
3708c2ecf20Sopenharmony_ci		jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		clk_disable_unprepare(i2s->clk_i2s);
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	clk_disable_unprepare(i2s->clk_aic);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return 0;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic int jz4740_i2s_resume(struct snd_soc_component *component)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_component_get_drvdata(component);
3838c2ecf20Sopenharmony_ci	uint32_t conf;
3848c2ecf20Sopenharmony_ci	int ret;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(i2s->clk_aic);
3878c2ecf20Sopenharmony_ci	if (ret)
3888c2ecf20Sopenharmony_ci		return ret;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (snd_soc_component_active(component)) {
3918c2ecf20Sopenharmony_ci		ret = clk_prepare_enable(i2s->clk_i2s);
3928c2ecf20Sopenharmony_ci		if (ret) {
3938c2ecf20Sopenharmony_ci			clk_disable_unprepare(i2s->clk_aic);
3948c2ecf20Sopenharmony_ci			return ret;
3958c2ecf20Sopenharmony_ci		}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
3988c2ecf20Sopenharmony_ci		conf |= JZ_AIC_CONF_ENABLE;
3998c2ecf20Sopenharmony_ci		jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	return 0;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	struct snd_dmaengine_dai_dma_data *dma_data;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* Playback */
4108c2ecf20Sopenharmony_ci	dma_data = &i2s->playback_dma_data;
4118c2ecf20Sopenharmony_ci	dma_data->maxburst = 16;
4128c2ecf20Sopenharmony_ci	dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT;
4138c2ecf20Sopenharmony_ci	dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* Capture */
4168c2ecf20Sopenharmony_ci	dma_data = &i2s->capture_dma_data;
4178c2ecf20Sopenharmony_ci	dma_data->maxburst = 16;
4188c2ecf20Sopenharmony_ci	dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE;
4198c2ecf20Sopenharmony_ci	dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int jz4740_i2s_dai_probe(struct snd_soc_dai *dai)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
4258c2ecf20Sopenharmony_ci	uint32_t conf;
4268c2ecf20Sopenharmony_ci	int ret;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(i2s->clk_aic);
4298c2ecf20Sopenharmony_ci	if (ret)
4308c2ecf20Sopenharmony_ci		return ret;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	jz4740_i2c_init_pcm_config(i2s);
4338c2ecf20Sopenharmony_ci	snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
4348c2ecf20Sopenharmony_ci		&i2s->capture_dma_data);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (i2s->soc_info->version >= JZ_I2S_JZ4760) {
4378c2ecf20Sopenharmony_ci		conf = (7 << JZ4760_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
4388c2ecf20Sopenharmony_ci			(8 << JZ4760_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
4398c2ecf20Sopenharmony_ci			JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
4408c2ecf20Sopenharmony_ci			JZ_AIC_CONF_I2S |
4418c2ecf20Sopenharmony_ci			JZ_AIC_CONF_INTERNAL_CODEC;
4428c2ecf20Sopenharmony_ci	} else {
4438c2ecf20Sopenharmony_ci		conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) |
4448c2ecf20Sopenharmony_ci			(8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) |
4458c2ecf20Sopenharmony_ci			JZ_AIC_CONF_OVERFLOW_PLAY_LAST |
4468c2ecf20Sopenharmony_ci			JZ_AIC_CONF_I2S |
4478c2ecf20Sopenharmony_ci			JZ_AIC_CONF_INTERNAL_CODEC;
4488c2ecf20Sopenharmony_ci	}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, JZ_AIC_CONF_RESET);
4518c2ecf20Sopenharmony_ci	jz4740_i2s_write(i2s, JZ_REG_AIC_CONF, conf);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	return 0;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic int jz4740_i2s_dai_remove(struct snd_soc_dai *dai)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	clk_disable_unprepare(i2s->clk_aic);
4618c2ecf20Sopenharmony_ci	return 0;
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops jz4740_i2s_dai_ops = {
4658c2ecf20Sopenharmony_ci	.startup = jz4740_i2s_startup,
4668c2ecf20Sopenharmony_ci	.shutdown = jz4740_i2s_shutdown,
4678c2ecf20Sopenharmony_ci	.trigger = jz4740_i2s_trigger,
4688c2ecf20Sopenharmony_ci	.hw_params = jz4740_i2s_hw_params,
4698c2ecf20Sopenharmony_ci	.set_fmt = jz4740_i2s_set_fmt,
4708c2ecf20Sopenharmony_ci	.set_sysclk = jz4740_i2s_set_sysclk,
4718c2ecf20Sopenharmony_ci};
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci#define JZ4740_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | \
4748c2ecf20Sopenharmony_ci		SNDRV_PCM_FMTBIT_S16_LE)
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver jz4740_i2s_dai = {
4778c2ecf20Sopenharmony_ci	.probe = jz4740_i2s_dai_probe,
4788c2ecf20Sopenharmony_ci	.remove = jz4740_i2s_dai_remove,
4798c2ecf20Sopenharmony_ci	.playback = {
4808c2ecf20Sopenharmony_ci		.channels_min = 1,
4818c2ecf20Sopenharmony_ci		.channels_max = 2,
4828c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_8000_48000,
4838c2ecf20Sopenharmony_ci		.formats = JZ4740_I2S_FMTS,
4848c2ecf20Sopenharmony_ci	},
4858c2ecf20Sopenharmony_ci	.capture = {
4868c2ecf20Sopenharmony_ci		.channels_min = 2,
4878c2ecf20Sopenharmony_ci		.channels_max = 2,
4888c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_8000_48000,
4898c2ecf20Sopenharmony_ci		.formats = JZ4740_I2S_FMTS,
4908c2ecf20Sopenharmony_ci	},
4918c2ecf20Sopenharmony_ci	.symmetric_rates = 1,
4928c2ecf20Sopenharmony_ci	.ops = &jz4740_i2s_dai_ops,
4938c2ecf20Sopenharmony_ci};
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic const struct i2s_soc_info jz4740_i2s_soc_info = {
4968c2ecf20Sopenharmony_ci	.version = JZ_I2S_JZ4740,
4978c2ecf20Sopenharmony_ci	.dai = &jz4740_i2s_dai,
4988c2ecf20Sopenharmony_ci	.shared_fifo_flush = true,
4998c2ecf20Sopenharmony_ci};
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic const struct i2s_soc_info jz4760_i2s_soc_info = {
5028c2ecf20Sopenharmony_ci	.version = JZ_I2S_JZ4760,
5038c2ecf20Sopenharmony_ci	.dai = &jz4740_i2s_dai,
5048c2ecf20Sopenharmony_ci};
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver jz4770_i2s_dai = {
5078c2ecf20Sopenharmony_ci	.probe = jz4740_i2s_dai_probe,
5088c2ecf20Sopenharmony_ci	.remove = jz4740_i2s_dai_remove,
5098c2ecf20Sopenharmony_ci	.playback = {
5108c2ecf20Sopenharmony_ci		.channels_min = 1,
5118c2ecf20Sopenharmony_ci		.channels_max = 2,
5128c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_8000_48000,
5138c2ecf20Sopenharmony_ci		.formats = JZ4740_I2S_FMTS,
5148c2ecf20Sopenharmony_ci	},
5158c2ecf20Sopenharmony_ci	.capture = {
5168c2ecf20Sopenharmony_ci		.channels_min = 2,
5178c2ecf20Sopenharmony_ci		.channels_max = 2,
5188c2ecf20Sopenharmony_ci		.rates = SNDRV_PCM_RATE_8000_48000,
5198c2ecf20Sopenharmony_ci		.formats = JZ4740_I2S_FMTS,
5208c2ecf20Sopenharmony_ci	},
5218c2ecf20Sopenharmony_ci	.ops = &jz4740_i2s_dai_ops,
5228c2ecf20Sopenharmony_ci};
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic const struct i2s_soc_info jz4770_i2s_soc_info = {
5258c2ecf20Sopenharmony_ci	.version = JZ_I2S_JZ4770,
5268c2ecf20Sopenharmony_ci	.dai = &jz4770_i2s_dai,
5278c2ecf20Sopenharmony_ci};
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic const struct i2s_soc_info jz4780_i2s_soc_info = {
5308c2ecf20Sopenharmony_ci	.version = JZ_I2S_JZ4780,
5318c2ecf20Sopenharmony_ci	.dai = &jz4770_i2s_dai,
5328c2ecf20Sopenharmony_ci};
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver jz4740_i2s_component = {
5358c2ecf20Sopenharmony_ci	.name		= "jz4740-i2s",
5368c2ecf20Sopenharmony_ci	.suspend	= jz4740_i2s_suspend,
5378c2ecf20Sopenharmony_ci	.resume		= jz4740_i2s_resume,
5388c2ecf20Sopenharmony_ci};
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic const struct of_device_id jz4740_of_matches[] = {
5418c2ecf20Sopenharmony_ci	{ .compatible = "ingenic,jz4740-i2s", .data = &jz4740_i2s_soc_info },
5428c2ecf20Sopenharmony_ci	{ .compatible = "ingenic,jz4760-i2s", .data = &jz4760_i2s_soc_info },
5438c2ecf20Sopenharmony_ci	{ .compatible = "ingenic,jz4770-i2s", .data = &jz4770_i2s_soc_info },
5448c2ecf20Sopenharmony_ci	{ .compatible = "ingenic,jz4780-i2s", .data = &jz4780_i2s_soc_info },
5458c2ecf20Sopenharmony_ci	{ /* sentinel */ }
5468c2ecf20Sopenharmony_ci};
5478c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, jz4740_of_matches);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic int jz4740_i2s_dev_probe(struct platform_device *pdev)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
5528c2ecf20Sopenharmony_ci	struct jz4740_i2s *i2s;
5538c2ecf20Sopenharmony_ci	struct resource *mem;
5548c2ecf20Sopenharmony_ci	int ret;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL);
5578c2ecf20Sopenharmony_ci	if (!i2s)
5588c2ecf20Sopenharmony_ci		return -ENOMEM;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	i2s->soc_info = device_get_match_data(dev);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5638c2ecf20Sopenharmony_ci	i2s->base = devm_ioremap_resource(dev, mem);
5648c2ecf20Sopenharmony_ci	if (IS_ERR(i2s->base))
5658c2ecf20Sopenharmony_ci		return PTR_ERR(i2s->base);
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	i2s->phys_base = mem->start;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	i2s->clk_aic = devm_clk_get(dev, "aic");
5708c2ecf20Sopenharmony_ci	if (IS_ERR(i2s->clk_aic))
5718c2ecf20Sopenharmony_ci		return PTR_ERR(i2s->clk_aic);
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	i2s->clk_i2s = devm_clk_get(dev, "i2s");
5748c2ecf20Sopenharmony_ci	if (IS_ERR(i2s->clk_i2s))
5758c2ecf20Sopenharmony_ci		return PTR_ERR(i2s->clk_i2s);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, i2s);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	ret = devm_snd_soc_register_component(dev, &jz4740_i2s_component,
5808c2ecf20Sopenharmony_ci					      i2s->soc_info->dai, 1);
5818c2ecf20Sopenharmony_ci	if (ret)
5828c2ecf20Sopenharmony_ci		return ret;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	return devm_snd_dmaengine_pcm_register(dev, NULL,
5858c2ecf20Sopenharmony_ci		SND_DMAENGINE_PCM_FLAG_COMPAT);
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic struct platform_driver jz4740_i2s_driver = {
5898c2ecf20Sopenharmony_ci	.probe = jz4740_i2s_dev_probe,
5908c2ecf20Sopenharmony_ci	.driver = {
5918c2ecf20Sopenharmony_ci		.name = "jz4740-i2s",
5928c2ecf20Sopenharmony_ci		.of_match_table = jz4740_of_matches,
5938c2ecf20Sopenharmony_ci	},
5948c2ecf20Sopenharmony_ci};
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_cimodule_platform_driver(jz4740_i2s_driver);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ciMODULE_AUTHOR("Lars-Peter Clausen, <lars@metafoo.de>");
5998c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Ingenic JZ4740 SoC I2S driver");
6008c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
6018c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:jz4740-i2s");
602