brintos

brintos / linux-shallow public Read only

0
0
Text · 45.8 KiB · 40de99a Raw
1700 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2015 Andrea Venturi4 * Andrea Venturi <be17068@iperbole.bo.it>5 *6 * Copyright (C) 2016 Maxime Ripard7 * Maxime Ripard <maxime.ripard@free-electrons.com>8 */9 10#include <linux/clk.h>11#include <linux/dmaengine.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/platform_device.h>15#include <linux/pm_runtime.h>16#include <linux/regmap.h>17#include <linux/reset.h>18 19#include <sound/dmaengine_pcm.h>20#include <sound/pcm_params.h>21#include <sound/soc.h>22#include <sound/soc-dai.h>23 24#define SUN4I_I2S_CTRL_REG		0x0025#define SUN4I_I2S_CTRL_SDO_EN_MASK		GENMASK(11, 8)26#define SUN4I_I2S_CTRL_SDO_EN(sdo)			BIT(8 + (sdo))27#define SUN4I_I2S_CTRL_MODE_MASK		BIT(5)28#define SUN4I_I2S_CTRL_MODE_SLAVE			(1 << 5)29#define SUN4I_I2S_CTRL_MODE_MASTER			(0 << 5)30#define SUN4I_I2S_CTRL_TX_EN			BIT(2)31#define SUN4I_I2S_CTRL_RX_EN			BIT(1)32#define SUN4I_I2S_CTRL_GL_EN			BIT(0)33 34#define SUN4I_I2S_FMT0_REG		0x0435#define SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK	BIT(7)36#define SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED		(1 << 7)37#define SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL		(0 << 7)38#define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK	BIT(6)39#define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED		(1 << 6)40#define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL		(0 << 6)41#define SUN4I_I2S_FMT0_SR_MASK			GENMASK(5, 4)42#define SUN4I_I2S_FMT0_SR(sr)				((sr) << 4)43#define SUN4I_I2S_FMT0_WSS_MASK			GENMASK(3, 2)44#define SUN4I_I2S_FMT0_WSS(wss)				((wss) << 2)45#define SUN4I_I2S_FMT0_FMT_MASK			GENMASK(1, 0)46#define SUN4I_I2S_FMT0_FMT_RIGHT_J			(2 << 0)47#define SUN4I_I2S_FMT0_FMT_LEFT_J			(1 << 0)48#define SUN4I_I2S_FMT0_FMT_I2S				(0 << 0)49 50#define SUN4I_I2S_FMT1_REG		0x0851#define SUN4I_I2S_FMT1_REG_SEXT_MASK		BIT(8)52#define SUN4I_I2S_FMT1_REG_SEXT(sext)			((sext) << 8)53 54#define SUN4I_I2S_FIFO_TX_REG		0x0c55#define SUN4I_I2S_FIFO_RX_REG		0x1056 57#define SUN4I_I2S_FIFO_CTRL_REG		0x1458#define SUN4I_I2S_FIFO_CTRL_FLUSH_TX		BIT(25)59#define SUN4I_I2S_FIFO_CTRL_FLUSH_RX		BIT(24)60#define SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK	BIT(2)61#define SUN4I_I2S_FIFO_CTRL_TX_MODE(mode)		((mode) << 2)62#define SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK	GENMASK(1, 0)63#define SUN4I_I2S_FIFO_CTRL_RX_MODE(mode)		(mode)64 65#define SUN4I_I2S_FIFO_STA_REG		0x1866 67#define SUN4I_I2S_DMA_INT_CTRL_REG	0x1c68#define SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN	BIT(7)69#define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN	BIT(3)70 71#define SUN4I_I2S_INT_STA_REG		0x2072 73#define SUN4I_I2S_CLK_DIV_REG		0x2474#define SUN4I_I2S_CLK_DIV_MCLK_EN		BIT(7)75#define SUN4I_I2S_CLK_DIV_BCLK_MASK		GENMASK(6, 4)76#define SUN4I_I2S_CLK_DIV_BCLK(bclk)			((bclk) << 4)77#define SUN4I_I2S_CLK_DIV_MCLK_MASK		GENMASK(3, 0)78#define SUN4I_I2S_CLK_DIV_MCLK(mclk)			((mclk) << 0)79 80#define SUN4I_I2S_TX_CNT_REG		0x2881#define SUN4I_I2S_RX_CNT_REG		0x2c82 83#define SUN4I_I2S_TX_CHAN_SEL_REG	0x3084#define SUN4I_I2S_CHAN_SEL_MASK			GENMASK(2, 0)85#define SUN4I_I2S_CHAN_SEL(num_chan)		(((num_chan) - 1) << 0)86 87#define SUN4I_I2S_TX_CHAN_MAP_REG	0x3488#define SUN4I_I2S_TX_CHAN_MAP(chan, sample)	((sample) << (chan << 2))89 90#define SUN4I_I2S_RX_CHAN_SEL_REG	0x3891#define SUN4I_I2S_RX_CHAN_MAP_REG	0x3c92 93/* Defines required for sun8i-h3 support */94#define SUN8I_I2S_CTRL_BCLK_OUT			BIT(18)95#define SUN8I_I2S_CTRL_LRCK_OUT			BIT(17)96 97#define SUN8I_I2S_CTRL_MODE_MASK		GENMASK(5, 4)98#define SUN8I_I2S_CTRL_MODE_RIGHT		(2 << 4)99#define SUN8I_I2S_CTRL_MODE_LEFT		(1 << 4)100#define SUN8I_I2S_CTRL_MODE_PCM			(0 << 4)101 102#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK	BIT(19)103#define SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH	(1 << 19)104#define SUN8I_I2S_FMT0_LRCLK_POLARITY_START_LOW		(0 << 19)105#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK		GENMASK(17, 8)106#define SUN8I_I2S_FMT0_LRCK_PERIOD(period)	((period - 1) << 8)107#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK	BIT(7)108#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED		(1 << 7)109#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL		(0 << 7)110 111#define SUN8I_I2S_FMT1_REG_SEXT_MASK		GENMASK(5, 4)112#define SUN8I_I2S_FMT1_REG_SEXT(sext)			((sext) << 4)113 114#define SUN8I_I2S_INT_STA_REG		0x0c115#define SUN8I_I2S_FIFO_TX_REG		0x20116 117#define SUN8I_I2S_CHAN_CFG_REG		0x30118#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK	GENMASK(7, 4)119#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)	((chan - 1) << 4)120#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK	GENMASK(3, 0)121#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan)	(chan - 1)122 123#define SUN8I_I2S_TX_CHAN_MAP_REG	0x44124#define SUN8I_I2S_TX_CHAN_SEL_REG	0x34125#define SUN8I_I2S_TX_CHAN_OFFSET_MASK		GENMASK(13, 12)126#define SUN8I_I2S_TX_CHAN_OFFSET(offset)	(offset << 12)127#define SUN8I_I2S_TX_CHAN_EN_MASK		GENMASK(11, 4)128#define SUN8I_I2S_TX_CHAN_EN(num_chan)		(((1 << num_chan) - 1) << 4)129 130#define SUN8I_I2S_RX_CHAN_SEL_REG	0x54131#define SUN8I_I2S_RX_CHAN_MAP_REG	0x58132 133/* Defines required for sun50i-h6 support */134#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK	GENMASK(21, 20)135#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)	((offset) << 20)136#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK		GENMASK(19, 16)137#define SUN50I_H6_I2S_TX_CHAN_SEL(chan)		((chan - 1) << 16)138#define SUN50I_H6_I2S_TX_CHAN_EN_MASK		GENMASK(15, 0)139#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan)	(((1 << num_chan) - 1))140 141#define SUN50I_H6_I2S_TX_CHAN_SEL_REG(pin)	(0x34 + 4 * (pin))142#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG(pin)	(0x44 + 8 * (pin))143#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG(pin)	(0x48 + 8 * (pin))144 145#define SUN50I_H6_I2S_RX_CHAN_SEL_REG	0x64146#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG	0x68147#define SUN50I_H6_I2S_RX_CHAN_MAP1_REG	0x6C148 149#define SUN50I_R329_I2S_RX_CHAN_MAP0_REG 0x68150#define SUN50I_R329_I2S_RX_CHAN_MAP1_REG 0x6c151#define SUN50I_R329_I2S_RX_CHAN_MAP2_REG 0x70152#define SUN50I_R329_I2S_RX_CHAN_MAP3_REG 0x74153 154struct sun4i_i2s;155 156/**157 * struct sun4i_i2s_quirks - Differences between SoC variants.158 * @has_reset: SoC needs reset deasserted.159 * @pcm_formats: available PCM formats.160 * @reg_offset_txdata: offset of the tx fifo.161 * @sun4i_i2s_regmap: regmap config to use.162 * @field_clkdiv_mclk_en: regmap field to enable mclk output.163 * @field_fmt_wss: regmap field to set word select size.164 * @field_fmt_sr: regmap field to set sample resolution.165 * @num_din_pins: input pins166 * @num_dout_pins: output pins (currently set but unused)167 * @bclk_dividers: bit clock dividers array168 * @num_bclk_dividers: number of bit clock dividers169 * @mclk_dividers: mclk dividers array170 * @num_mclk_dividers: number of mclk dividers171 * @get_bclk_parent_rate: callback to get bclk parent rate172 * @get_sr: callback to get sample resolution173 * @get_wss: callback to get word select size174 * @set_chan_cfg: callback to set channel configuration175 * @set_fmt: callback to set format176 */177struct sun4i_i2s_quirks {178	bool				has_reset;179	u64				pcm_formats;180	unsigned int			reg_offset_txdata;	/* TX FIFO */181	const struct regmap_config	*sun4i_i2s_regmap;182 183	/* Register fields for i2s */184	struct reg_field		field_clkdiv_mclk_en;185	struct reg_field		field_fmt_wss;186	struct reg_field		field_fmt_sr;187 188	unsigned int			num_din_pins;189	unsigned int			num_dout_pins;190 191	const struct sun4i_i2s_clk_div	*bclk_dividers;192	unsigned int			num_bclk_dividers;193	const struct sun4i_i2s_clk_div	*mclk_dividers;194	unsigned int			num_mclk_dividers;195 196	unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *i2s);197	int	(*get_sr)(unsigned int width);198	int	(*get_wss)(unsigned int width);199 200	/*201	 * In the set_chan_cfg() function pointer:202	 * @slots: channels per frame + padding slots, regardless of format203	 * @slot_width: bits per sample + padding bits, regardless of format204	 */205	int	(*set_chan_cfg)(const struct sun4i_i2s *i2s,206				unsigned int channels,	unsigned int slots,207				unsigned int slot_width);208	int	(*set_fmt)(const struct sun4i_i2s *i2s, unsigned int fmt);209};210 211struct sun4i_i2s {212	struct clk	*bus_clk;213	struct clk	*mod_clk;214	struct regmap	*regmap;215	struct reset_control *rst;216 217	unsigned int	format;218	unsigned int	mclk_freq;219	unsigned int	slots;220	unsigned int	slot_width;221 222	struct snd_dmaengine_dai_dma_data	capture_dma_data;223	struct snd_dmaengine_dai_dma_data	playback_dma_data;224 225	/* Register fields for i2s */226	struct regmap_field	*field_clkdiv_mclk_en;227	struct regmap_field	*field_fmt_wss;228	struct regmap_field	*field_fmt_sr;229 230	const struct sun4i_i2s_quirks	*variant;231};232 233struct sun4i_i2s_clk_div {234	u8	div;235	u8	val;236};237 238static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = {239	{ .div = 2, .val = 0 },240	{ .div = 4, .val = 1 },241	{ .div = 6, .val = 2 },242	{ .div = 8, .val = 3 },243	{ .div = 12, .val = 4 },244	{ .div = 16, .val = 5 },245	/* TODO - extend divide ratio supported by newer SoCs */246};247 248static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {249	{ .div = 1, .val = 0 },250	{ .div = 2, .val = 1 },251	{ .div = 4, .val = 2 },252	{ .div = 6, .val = 3 },253	{ .div = 8, .val = 4 },254	{ .div = 12, .val = 5 },255	{ .div = 16, .val = 6 },256	{ .div = 24, .val = 7 },257	/* TODO - extend divide ratio supported by newer SoCs */258};259 260static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = {261	{ .div = 1, .val = 1 },262	{ .div = 2, .val = 2 },263	{ .div = 4, .val = 3 },264	{ .div = 6, .val = 4 },265	{ .div = 8, .val = 5 },266	{ .div = 12, .val = 6 },267	{ .div = 16, .val = 7 },268	{ .div = 24, .val = 8 },269	{ .div = 32, .val = 9 },270	{ .div = 48, .val = 10 },271	{ .div = 64, .val = 11 },272	{ .div = 96, .val = 12 },273	{ .div = 128, .val = 13 },274	{ .div = 176, .val = 14 },275	{ .div = 192, .val = 15 },276};277 278static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)279{280	return i2s->mclk_freq;281}282 283static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)284{285	return clk_get_rate(i2s->mod_clk);286}287 288static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,289				  unsigned long parent_rate,290				  unsigned int sampling_rate,291				  unsigned int channels,292				  unsigned int word_size)293{294	const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers;295	int div = parent_rate / sampling_rate / word_size / channels;296	int i;297 298	for (i = 0; i < i2s->variant->num_bclk_dividers; i++) {299		const struct sun4i_i2s_clk_div *bdiv = &dividers[i];300 301		if (bdiv->div == div)302			return bdiv->val;303	}304 305	return -EINVAL;306}307 308static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,309				  unsigned long parent_rate,310				  unsigned long mclk_rate)311{312	const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers;313	int div = parent_rate / mclk_rate;314	int i;315 316	for (i = 0; i < i2s->variant->num_mclk_dividers; i++) {317		const struct sun4i_i2s_clk_div *mdiv = &dividers[i];318 319		if (mdiv->div == div)320			return mdiv->val;321	}322 323	return -EINVAL;324}325 326static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 };327static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)328{329	int i;330 331	for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++)332		if (sun4i_i2s_oversample_rates[i] == oversample)333			return true;334 335	return false;336}337 338static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,339				  unsigned int rate,340				  unsigned int slots,341				  unsigned int slot_width)342{343	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);344	unsigned int oversample_rate, clk_rate, bclk_parent_rate;345	int bclk_div, mclk_div;346	int ret;347 348	switch (rate) {349	case 176400:350	case 88200:351	case 44100:352	case 22050:353	case 11025:354		clk_rate = 22579200;355		break;356 357	case 192000:358	case 128000:359	case 96000:360	case 64000:361	case 48000:362	case 32000:363	case 24000:364	case 16000:365	case 12000:366	case 8000:367		clk_rate = 24576000;368		break;369 370	default:371		dev_err(dai->dev, "Unsupported sample rate: %u\n", rate);372		return -EINVAL;373	}374 375	ret = clk_set_rate(i2s->mod_clk, clk_rate);376	if (ret)377		return ret;378 379	oversample_rate = i2s->mclk_freq / rate;380	if (!sun4i_i2s_oversample_is_valid(oversample_rate)) {381		dev_err(dai->dev, "Unsupported oversample rate: %d\n",382			oversample_rate);383		return -EINVAL;384	}385 386	bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);387	bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,388					  rate, slots, slot_width);389	if (bclk_div < 0) {390		dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);391		return -EINVAL;392	}393 394	mclk_div = sun4i_i2s_get_mclk_div(i2s, clk_rate, i2s->mclk_freq);395	if (mclk_div < 0) {396		dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div);397		return -EINVAL;398	}399 400	regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,401		     SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |402		     SUN4I_I2S_CLK_DIV_MCLK(mclk_div));403 404	regmap_field_write(i2s->field_clkdiv_mclk_en, 1);405 406	return 0;407}408 409static int sun4i_i2s_get_sr(unsigned int width)410{411	switch (width) {412	case 16:413		return 0;414	case 20:415		return 1;416	case 24:417		return 2;418	}419 420	return -EINVAL;421}422 423static int sun4i_i2s_get_wss(unsigned int width)424{425	switch (width) {426	case 16:427		return 0;428	case 20:429		return 1;430	case 24:431		return 2;432	case 32:433		return 3;434	}435 436	return -EINVAL;437}438 439static int sun8i_i2s_get_sr_wss(unsigned int width)440{441	switch (width) {442	case 8:443		return 1;444	case 12:445		return 2;446	case 16:447		return 3;448	case 20:449		return 4;450	case 24:451		return 5;452	case 28:453		return 6;454	case 32:455		return 7;456	}457 458	return -EINVAL;459}460 461static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,462				  unsigned int channels, unsigned int slots,463				  unsigned int slot_width)464{465	/* Map the channels for playback and capture */466	regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);467	regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);468 469	/* Configure the channels */470	regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,471			   SUN4I_I2S_CHAN_SEL_MASK,472			   SUN4I_I2S_CHAN_SEL(channels));473	regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG,474			   SUN4I_I2S_CHAN_SEL_MASK,475			   SUN4I_I2S_CHAN_SEL(channels));476 477	return 0;478}479 480static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,481				  unsigned int channels, unsigned int slots,482				  unsigned int slot_width)483{484	unsigned int lrck_period;485 486	/* Map the channels for playback and capture */487	regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);488	regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);489 490	/* Configure the channels */491	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,492			   SUN4I_I2S_CHAN_SEL_MASK,493			   SUN4I_I2S_CHAN_SEL(channels));494	regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,495			   SUN4I_I2S_CHAN_SEL_MASK,496			   SUN4I_I2S_CHAN_SEL(channels));497 498	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,499			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,500			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));501	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,502			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,503			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));504 505	switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {506	case SND_SOC_DAIFMT_DSP_A:507	case SND_SOC_DAIFMT_DSP_B:508		lrck_period = slot_width * slots;509		break;510 511	case SND_SOC_DAIFMT_LEFT_J:512	case SND_SOC_DAIFMT_RIGHT_J:513	case SND_SOC_DAIFMT_I2S:514		lrck_period = slot_width;515		break;516 517	default:518		return -EINVAL;519	}520 521	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,522			   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,523			   SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));524 525	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,526			   SUN8I_I2S_TX_CHAN_EN_MASK,527			   SUN8I_I2S_TX_CHAN_EN(channels));528 529	return 0;530}531 532static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,533				      unsigned int channels, unsigned int slots,534				      unsigned int slot_width)535{536	unsigned int lrck_period;537 538	/* Map the channels for playback and capture */539	regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0xFEDCBA98);540	regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x76543210);541	if (i2s->variant->num_din_pins > 1) {542		regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP0_REG, 0x0F0E0D0C);543		regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP1_REG, 0x0B0A0908);544		regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP2_REG, 0x07060504);545		regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP3_REG, 0x03020100);546	} else {547		regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98);548		regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210);549	}550 551	/* Configure the channels */552	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0),553			   SUN50I_H6_I2S_TX_CHAN_SEL_MASK,554			   SUN50I_H6_I2S_TX_CHAN_SEL(channels));555	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,556			   SUN50I_H6_I2S_TX_CHAN_SEL_MASK,557			   SUN50I_H6_I2S_TX_CHAN_SEL(channels));558 559	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,560			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,561			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));562	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,563			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,564			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));565 566	switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {567	case SND_SOC_DAIFMT_DSP_A:568	case SND_SOC_DAIFMT_DSP_B:569		lrck_period = slot_width * slots;570		break;571 572	case SND_SOC_DAIFMT_LEFT_J:573	case SND_SOC_DAIFMT_RIGHT_J:574	case SND_SOC_DAIFMT_I2S:575		lrck_period = slot_width;576		break;577 578	default:579		return -EINVAL;580	}581 582	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,583			   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,584			   SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));585 586	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0),587			   SUN50I_H6_I2S_TX_CHAN_EN_MASK,588			   SUN50I_H6_I2S_TX_CHAN_EN(channels));589 590	return 0;591}592 593static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,594			       struct snd_pcm_hw_params *params,595			       struct snd_soc_dai *dai)596{597	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);598	unsigned int word_size = params_width(params);599	unsigned int slot_width = params_physical_width(params);600	unsigned int channels = params_channels(params);601 602	unsigned int slots = channels;603 604	int ret, sr, wss;605	u32 width;606 607	if (i2s->slots)608		slots = i2s->slots;609 610	if (i2s->slot_width)611		slot_width = i2s->slot_width;612 613	ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width);614	if (ret < 0) {615		dev_err(dai->dev, "Invalid channel configuration\n");616		return ret;617	}618 619	/* Set significant bits in our FIFOs */620	regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,621			   SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |622			   SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,623			   SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |624			   SUN4I_I2S_FIFO_CTRL_RX_MODE(1));625 626	switch (params_physical_width(params)) {627	case 16:628		width = DMA_SLAVE_BUSWIDTH_2_BYTES;629		break;630	case 32:631		width = DMA_SLAVE_BUSWIDTH_4_BYTES;632		break;633	default:634		dev_err(dai->dev, "Unsupported physical sample width: %d\n",635			params_physical_width(params));636		return -EINVAL;637	}638	i2s->playback_dma_data.addr_width = width;639 640	sr = i2s->variant->get_sr(word_size);641	if (sr < 0)642		return -EINVAL;643 644	wss = i2s->variant->get_wss(slot_width);645	if (wss < 0)646		return -EINVAL;647 648	regmap_field_write(i2s->field_fmt_wss, wss);649	regmap_field_write(i2s->field_fmt_sr, sr);650 651	return sun4i_i2s_set_clk_rate(dai, params_rate(params),652				      slots, slot_width);653}654 655static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,656				 unsigned int fmt)657{658	u32 val;659 660	/* DAI clock polarity */661	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {662	case SND_SOC_DAIFMT_IB_IF:663		/* Invert both clocks */664		val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |665		      SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;666		break;667	case SND_SOC_DAIFMT_IB_NF:668		/* Invert bit clock */669		val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED;670		break;671	case SND_SOC_DAIFMT_NB_IF:672		/* Invert frame clock */673		val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;674		break;675	case SND_SOC_DAIFMT_NB_NF:676		val = 0;677		break;678	default:679		return -EINVAL;680	}681 682	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,683			   SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK |684			   SUN4I_I2S_FMT0_BCLK_POLARITY_MASK,685			   val);686 687	/* DAI Mode */688	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {689	case SND_SOC_DAIFMT_I2S:690		val = SUN4I_I2S_FMT0_FMT_I2S;691		break;692 693	case SND_SOC_DAIFMT_LEFT_J:694		val = SUN4I_I2S_FMT0_FMT_LEFT_J;695		break;696 697	case SND_SOC_DAIFMT_RIGHT_J:698		val = SUN4I_I2S_FMT0_FMT_RIGHT_J;699		break;700 701	default:702		return -EINVAL;703	}704 705	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,706			   SUN4I_I2S_FMT0_FMT_MASK, val);707 708	/* DAI clock master masks */709	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {710	case SND_SOC_DAIFMT_BP_FP:711		/* BCLK and LRCLK master */712		val = SUN4I_I2S_CTRL_MODE_MASTER;713		break;714 715	case SND_SOC_DAIFMT_BC_FC:716		/* BCLK and LRCLK slave */717		val = SUN4I_I2S_CTRL_MODE_SLAVE;718		break;719 720	default:721		return -EINVAL;722	}723	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,724			   SUN4I_I2S_CTRL_MODE_MASK, val);725 726	return 0;727}728 729static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,730				 unsigned int fmt)731{732	u32 mode, lrclk_pol, bclk_pol, val;733	u8 offset;734 735	/* DAI Mode */736	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {737	case SND_SOC_DAIFMT_DSP_A:738		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;739		mode = SUN8I_I2S_CTRL_MODE_PCM;740		offset = 1;741		break;742 743	case SND_SOC_DAIFMT_DSP_B:744		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;745		mode = SUN8I_I2S_CTRL_MODE_PCM;746		offset = 0;747		break;748 749	case SND_SOC_DAIFMT_I2S:750		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_LOW;751		mode = SUN8I_I2S_CTRL_MODE_LEFT;752		offset = 1;753		break;754 755	case SND_SOC_DAIFMT_LEFT_J:756		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;757		mode = SUN8I_I2S_CTRL_MODE_LEFT;758		offset = 0;759		break;760 761	case SND_SOC_DAIFMT_RIGHT_J:762		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;763		mode = SUN8I_I2S_CTRL_MODE_RIGHT;764		offset = 0;765		break;766 767	default:768		return -EINVAL;769	}770 771	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,772			   SUN8I_I2S_CTRL_MODE_MASK, mode);773	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,774			   SUN8I_I2S_TX_CHAN_OFFSET_MASK,775			   SUN8I_I2S_TX_CHAN_OFFSET(offset));776	regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,777			   SUN8I_I2S_TX_CHAN_OFFSET_MASK,778			   SUN8I_I2S_TX_CHAN_OFFSET(offset));779 780	/* DAI clock polarity */781	bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL;782 783	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {784	case SND_SOC_DAIFMT_IB_IF:785		/* Invert both clocks */786		lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;787		bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;788		break;789	case SND_SOC_DAIFMT_IB_NF:790		/* Invert bit clock */791		bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;792		break;793	case SND_SOC_DAIFMT_NB_IF:794		/* Invert frame clock */795		lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;796		break;797	case SND_SOC_DAIFMT_NB_NF:798		/* No inversion */799		break;800	default:801		return -EINVAL;802	}803 804	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,805			   SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |806			   SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,807			   lrclk_pol | bclk_pol);808 809	/* DAI clock master masks */810	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {811	case SND_SOC_DAIFMT_BP_FP:812		/* BCLK and LRCLK master */813		val = SUN8I_I2S_CTRL_BCLK_OUT |	SUN8I_I2S_CTRL_LRCK_OUT;814		break;815 816	case SND_SOC_DAIFMT_BC_FC:817		/* BCLK and LRCLK slave */818		val = 0;819		break;820 821	default:822		return -EINVAL;823	}824 825	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,826			   SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,827			   val);828 829	/* Set sign extension to pad out LSB with 0 */830	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,831			   SUN8I_I2S_FMT1_REG_SEXT_MASK,832			   SUN8I_I2S_FMT1_REG_SEXT(0));833 834	return 0;835}836 837static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,838				     unsigned int fmt)839{840	u32 mode, lrclk_pol, bclk_pol, val;841	u8 offset;842 843	/* DAI Mode */844	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {845	case SND_SOC_DAIFMT_DSP_A:846		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;847		mode = SUN8I_I2S_CTRL_MODE_PCM;848		offset = 1;849		break;850 851	case SND_SOC_DAIFMT_DSP_B:852		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;853		mode = SUN8I_I2S_CTRL_MODE_PCM;854		offset = 0;855		break;856 857	case SND_SOC_DAIFMT_I2S:858		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_LOW;859		mode = SUN8I_I2S_CTRL_MODE_LEFT;860		offset = 1;861		break;862 863	case SND_SOC_DAIFMT_LEFT_J:864		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;865		mode = SUN8I_I2S_CTRL_MODE_LEFT;866		offset = 0;867		break;868 869	case SND_SOC_DAIFMT_RIGHT_J:870		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;871		mode = SUN8I_I2S_CTRL_MODE_RIGHT;872		offset = 0;873		break;874 875	default:876		return -EINVAL;877	}878 879	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,880			   SUN8I_I2S_CTRL_MODE_MASK, mode);881	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,882			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,883			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));884	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,885			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,886			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));887 888	/* DAI clock polarity */889	bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL;890 891	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {892	case SND_SOC_DAIFMT_IB_IF:893		/* Invert both clocks */894		lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;895		bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;896		break;897	case SND_SOC_DAIFMT_IB_NF:898		/* Invert bit clock */899		bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;900		break;901	case SND_SOC_DAIFMT_NB_IF:902		/* Invert frame clock */903		lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;904		break;905	case SND_SOC_DAIFMT_NB_NF:906		/* No inversion */907		break;908	default:909		return -EINVAL;910	}911 912	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,913			   SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |914			   SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,915			   lrclk_pol | bclk_pol);916 917 918	/* DAI clock master masks */919	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {920	case SND_SOC_DAIFMT_BP_FP:921		/* BCLK and LRCLK master */922		val = SUN8I_I2S_CTRL_BCLK_OUT |	SUN8I_I2S_CTRL_LRCK_OUT;923		break;924 925	case SND_SOC_DAIFMT_BC_FC:926		/* BCLK and LRCLK slave */927		val = 0;928		break;929 930	default:931		return -EINVAL;932	}933 934	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,935			   SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,936			   val);937 938	/* Set sign extension to pad out LSB with 0 */939	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,940			   SUN8I_I2S_FMT1_REG_SEXT_MASK,941			   SUN8I_I2S_FMT1_REG_SEXT(0));942 943	return 0;944}945 946static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)947{948	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);949	int ret;950 951	ret = i2s->variant->set_fmt(i2s, fmt);952	if (ret) {953		dev_err(dai->dev, "Unsupported format configuration\n");954		return ret;955	}956 957	i2s->format = fmt;958 959	return 0;960}961 962static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)963{964	/* Flush RX FIFO */965	regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,966			   SUN4I_I2S_FIFO_CTRL_FLUSH_RX,967			   SUN4I_I2S_FIFO_CTRL_FLUSH_RX);968 969	/* Clear RX counter */970	regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0);971 972	/* Enable RX Block */973	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,974			   SUN4I_I2S_CTRL_RX_EN,975			   SUN4I_I2S_CTRL_RX_EN);976 977	/* Enable RX DRQ */978	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,979			   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,980			   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN);981}982 983static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)984{985	/* Flush TX FIFO */986	regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,987			   SUN4I_I2S_FIFO_CTRL_FLUSH_TX,988			   SUN4I_I2S_FIFO_CTRL_FLUSH_TX);989 990	/* Clear TX counter */991	regmap_write(i2s->regmap, SUN4I_I2S_TX_CNT_REG, 0);992 993	/* Enable TX Block */994	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,995			   SUN4I_I2S_CTRL_TX_EN,996			   SUN4I_I2S_CTRL_TX_EN);997 998	/* Enable TX DRQ */999	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,1000			   SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN,1001			   SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN);1002}1003 1004static void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s)1005{1006	/* Disable RX Block */1007	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,1008			   SUN4I_I2S_CTRL_RX_EN,1009			   0);1010 1011	/* Disable RX DRQ */1012	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,1013			   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,1014			   0);1015}1016 1017static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s)1018{1019	/* Disable TX Block */1020	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,1021			   SUN4I_I2S_CTRL_TX_EN,1022			   0);1023 1024	/* Disable TX DRQ */1025	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,1026			   SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN,1027			   0);1028}1029 1030static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,1031			     struct snd_soc_dai *dai)1032{1033	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);1034 1035	switch (cmd) {1036	case SNDRV_PCM_TRIGGER_START:1037	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:1038	case SNDRV_PCM_TRIGGER_RESUME:1039		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)1040			sun4i_i2s_start_playback(i2s);1041		else1042			sun4i_i2s_start_capture(i2s);1043		break;1044 1045	case SNDRV_PCM_TRIGGER_STOP:1046	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:1047	case SNDRV_PCM_TRIGGER_SUSPEND:1048		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)1049			sun4i_i2s_stop_playback(i2s);1050		else1051			sun4i_i2s_stop_capture(i2s);1052		break;1053 1054	default:1055		return -EINVAL;1056	}1057 1058	return 0;1059}1060 1061static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,1062				unsigned int freq, int dir)1063{1064	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);1065 1066	if (clk_id != 0)1067		return -EINVAL;1068 1069	i2s->mclk_freq = freq;1070 1071	return 0;1072}1073 1074static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,1075				  unsigned int tx_mask, unsigned int rx_mask,1076				  int slots, int slot_width)1077{1078	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);1079 1080	if (slots > 8)1081		return -EINVAL;1082 1083	i2s->slots = slots;1084	i2s->slot_width = slot_width;1085 1086	return 0;1087}1088 1089static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)1090{1091	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);1092 1093	snd_soc_dai_init_dma_data(dai,1094				  &i2s->playback_dma_data,1095				  &i2s->capture_dma_data);1096 1097	return 0;1098}1099 1100static int sun4i_i2s_dai_startup(struct snd_pcm_substream *sub, struct snd_soc_dai *dai)1101{1102	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);1103	struct snd_pcm_runtime *runtime = sub->runtime;1104 1105	return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT,1106					    i2s->variant->pcm_formats);1107}1108 1109static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {1110	.probe		= sun4i_i2s_dai_probe,1111	.startup	= sun4i_i2s_dai_startup,1112	.hw_params	= sun4i_i2s_hw_params,1113	.set_fmt	= sun4i_i2s_set_fmt,1114	.set_sysclk	= sun4i_i2s_set_sysclk,1115	.set_tdm_slot	= sun4i_i2s_set_tdm_slot,1116	.trigger	= sun4i_i2s_trigger,1117};1118 1119#define SUN4I_FORMATS_ALL (SNDRV_PCM_FMTBIT_S16_LE | \1120			   SNDRV_PCM_FMTBIT_S20_LE | \1121			   SNDRV_PCM_FMTBIT_S24_LE | \1122			   SNDRV_PCM_FMTBIT_S32_LE)1123 1124static struct snd_soc_dai_driver sun4i_i2s_dai = {1125	.capture = {1126		.stream_name = "Capture",1127		.channels_min = 1,1128		.channels_max = 8,1129		.rates = SNDRV_PCM_RATE_8000_192000,1130		.formats = SUN4I_FORMATS_ALL,1131	},1132	.playback = {1133		.stream_name = "Playback",1134		.channels_min = 1,1135		.channels_max = 8,1136		.rates = SNDRV_PCM_RATE_8000_192000,1137		.formats = SUN4I_FORMATS_ALL,1138	},1139	.ops = &sun4i_i2s_dai_ops,1140	.symmetric_rate = 1,1141};1142 1143static const struct snd_soc_component_driver sun4i_i2s_component = {1144	.name			= "sun4i-dai",1145	.legacy_dai_naming	= 1,1146};1147 1148static bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg)1149{1150	switch (reg) {1151	case SUN4I_I2S_FIFO_TX_REG:1152		return false;1153 1154	default:1155		return true;1156	}1157}1158 1159static bool sun4i_i2s_wr_reg(struct device *dev, unsigned int reg)1160{1161	switch (reg) {1162	case SUN4I_I2S_FIFO_RX_REG:1163	case SUN4I_I2S_FIFO_STA_REG:1164		return false;1165 1166	default:1167		return true;1168	}1169}1170 1171static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg)1172{1173	switch (reg) {1174	case SUN4I_I2S_FIFO_RX_REG:1175	case SUN4I_I2S_INT_STA_REG:1176	case SUN4I_I2S_RX_CNT_REG:1177	case SUN4I_I2S_TX_CNT_REG:1178		return true;1179 1180	default:1181		return false;1182	}1183}1184 1185static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)1186{1187	switch (reg) {1188	case SUN8I_I2S_FIFO_TX_REG:1189		return false;1190 1191	default:1192		return true;1193	}1194}1195 1196static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg)1197{1198	switch (reg) {1199	case SUN4I_I2S_FIFO_CTRL_REG:1200	case SUN4I_I2S_FIFO_RX_REG:1201	case SUN4I_I2S_FIFO_STA_REG:1202	case SUN4I_I2S_RX_CNT_REG:1203	case SUN4I_I2S_TX_CNT_REG:1204	case SUN8I_I2S_FIFO_TX_REG:1205	case SUN8I_I2S_INT_STA_REG:1206		return true;1207 1208	default:1209		return false;1210	}1211}1212 1213static const struct reg_default sun4i_i2s_reg_defaults[] = {1214	{ SUN4I_I2S_CTRL_REG, 0x00000000 },1215	{ SUN4I_I2S_FMT0_REG, 0x0000000c },1216	{ SUN4I_I2S_FMT1_REG, 0x00004020 },1217	{ SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },1218	{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },1219	{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },1220	{ SUN4I_I2S_TX_CHAN_SEL_REG, 0x00000001 },1221	{ SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210 },1222	{ SUN4I_I2S_RX_CHAN_SEL_REG, 0x00000001 },1223	{ SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 },1224};1225 1226static const struct reg_default sun8i_i2s_reg_defaults[] = {1227	{ SUN4I_I2S_CTRL_REG, 0x00060000 },1228	{ SUN4I_I2S_FMT0_REG, 0x00000033 },1229	{ SUN4I_I2S_FMT1_REG, 0x00000030 },1230	{ SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },1231	{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },1232	{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },1233	{ SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },1234	{ SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },1235	{ SUN8I_I2S_TX_CHAN_MAP_REG, 0x00000000 },1236	{ SUN8I_I2S_RX_CHAN_SEL_REG, 0x00000000 },1237	{ SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },1238};1239 1240static const struct reg_default sun50i_h6_i2s_reg_defaults[] = {1241	{ SUN4I_I2S_CTRL_REG, 0x00060000 },1242	{ SUN4I_I2S_FMT0_REG, 0x00000033 },1243	{ SUN4I_I2S_FMT1_REG, 0x00000030 },1244	{ SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },1245	{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },1246	{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },1247	{ SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },1248	{ SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), 0x00000000 },1249	{ SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0x00000000 },1250	{ SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x00000000 },1251	{ SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 },1252	{ SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 },1253	{ SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 },1254};1255 1256static const struct regmap_config sun4i_i2s_regmap_config = {1257	.reg_bits	= 32,1258	.reg_stride	= 4,1259	.val_bits	= 32,1260	.max_register	= SUN4I_I2S_RX_CHAN_MAP_REG,1261 1262	.cache_type	= REGCACHE_FLAT,1263	.reg_defaults	= sun4i_i2s_reg_defaults,1264	.num_reg_defaults	= ARRAY_SIZE(sun4i_i2s_reg_defaults),1265	.writeable_reg	= sun4i_i2s_wr_reg,1266	.readable_reg	= sun4i_i2s_rd_reg,1267	.volatile_reg	= sun4i_i2s_volatile_reg,1268};1269 1270static const struct regmap_config sun8i_i2s_regmap_config = {1271	.reg_bits	= 32,1272	.reg_stride	= 4,1273	.val_bits	= 32,1274	.max_register	= SUN8I_I2S_RX_CHAN_MAP_REG,1275	.cache_type	= REGCACHE_FLAT,1276	.reg_defaults	= sun8i_i2s_reg_defaults,1277	.num_reg_defaults	= ARRAY_SIZE(sun8i_i2s_reg_defaults),1278	.writeable_reg	= sun4i_i2s_wr_reg,1279	.readable_reg	= sun8i_i2s_rd_reg,1280	.volatile_reg	= sun8i_i2s_volatile_reg,1281};1282 1283static const struct regmap_config sun50i_h6_i2s_regmap_config = {1284	.reg_bits	= 32,1285	.reg_stride	= 4,1286	.val_bits	= 32,1287	.max_register	= SUN50I_R329_I2S_RX_CHAN_MAP3_REG,1288	.cache_type	= REGCACHE_FLAT,1289	.reg_defaults	= sun50i_h6_i2s_reg_defaults,1290	.num_reg_defaults	= ARRAY_SIZE(sun50i_h6_i2s_reg_defaults),1291	.writeable_reg	= sun4i_i2s_wr_reg,1292	.readable_reg	= sun8i_i2s_rd_reg,1293	.volatile_reg	= sun8i_i2s_volatile_reg,1294};1295 1296static int sun4i_i2s_runtime_resume(struct device *dev)1297{1298	struct sun4i_i2s *i2s = dev_get_drvdata(dev);1299	int ret;1300 1301	ret = clk_prepare_enable(i2s->bus_clk);1302	if (ret) {1303		dev_err(dev, "Failed to enable bus clock\n");1304		return ret;1305	}1306 1307	regcache_cache_only(i2s->regmap, false);1308	regcache_mark_dirty(i2s->regmap);1309 1310	ret = regcache_sync(i2s->regmap);1311	if (ret) {1312		dev_err(dev, "Failed to sync regmap cache\n");1313		goto err_disable_clk;1314	}1315 1316	/* Enable the whole hardware block */1317	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,1318			   SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);1319 1320	/* Enable the first output line */1321	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,1322			   SUN4I_I2S_CTRL_SDO_EN_MASK,1323			   SUN4I_I2S_CTRL_SDO_EN(0));1324 1325	ret = clk_prepare_enable(i2s->mod_clk);1326	if (ret) {1327		dev_err(dev, "Failed to enable module clock\n");1328		goto err_disable_clk;1329	}1330 1331	return 0;1332 1333err_disable_clk:1334	clk_disable_unprepare(i2s->bus_clk);1335	return ret;1336}1337 1338static int sun4i_i2s_runtime_suspend(struct device *dev)1339{1340	struct sun4i_i2s *i2s = dev_get_drvdata(dev);1341 1342	clk_disable_unprepare(i2s->mod_clk);1343 1344	/* Disable our output lines */1345	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,1346			   SUN4I_I2S_CTRL_SDO_EN_MASK, 0);1347 1348	/* Disable the whole hardware block */1349	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,1350			   SUN4I_I2S_CTRL_GL_EN, 0);1351 1352	regcache_cache_only(i2s->regmap, true);1353 1354	clk_disable_unprepare(i2s->bus_clk);1355 1356	return 0;1357}1358 1359#define SUN4I_FORMATS_A10 (SUN4I_FORMATS_ALL & ~SNDRV_PCM_FMTBIT_S32_LE)1360#define SUN4I_FORMATS_H3 SUN4I_FORMATS_ALL1361 1362static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {1363	.has_reset		= false,1364	.pcm_formats		= SUN4I_FORMATS_A10,1365	.reg_offset_txdata	= SUN4I_I2S_FIFO_TX_REG,1366	.sun4i_i2s_regmap	= &sun4i_i2s_regmap_config,1367	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),1368	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),1369	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),1370	.bclk_dividers		= sun4i_i2s_bclk_div,1371	.num_bclk_dividers	= ARRAY_SIZE(sun4i_i2s_bclk_div),1372	.mclk_dividers		= sun4i_i2s_mclk_div,1373	.num_mclk_dividers	= ARRAY_SIZE(sun4i_i2s_mclk_div),1374	.get_bclk_parent_rate	= sun4i_i2s_get_bclk_parent_rate,1375	.get_sr			= sun4i_i2s_get_sr,1376	.get_wss		= sun4i_i2s_get_wss,1377	.set_chan_cfg		= sun4i_i2s_set_chan_cfg,1378	.set_fmt		= sun4i_i2s_set_soc_fmt,1379};1380 1381static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {1382	.has_reset		= true,1383	.pcm_formats		= SUN4I_FORMATS_A10,1384	.reg_offset_txdata	= SUN4I_I2S_FIFO_TX_REG,1385	.sun4i_i2s_regmap	= &sun4i_i2s_regmap_config,1386	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),1387	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),1388	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),1389	.bclk_dividers		= sun4i_i2s_bclk_div,1390	.num_bclk_dividers	= ARRAY_SIZE(sun4i_i2s_bclk_div),1391	.mclk_dividers		= sun4i_i2s_mclk_div,1392	.num_mclk_dividers	= ARRAY_SIZE(sun4i_i2s_mclk_div),1393	.get_bclk_parent_rate	= sun4i_i2s_get_bclk_parent_rate,1394	.get_sr			= sun4i_i2s_get_sr,1395	.get_wss		= sun4i_i2s_get_wss,1396	.set_chan_cfg		= sun4i_i2s_set_chan_cfg,1397	.set_fmt		= sun4i_i2s_set_soc_fmt,1398};1399 1400/*1401 * This doesn't describe the TDM controller documented in the A83t1402 * datasheet, but the three undocumented I2S controller that use the1403 * older design.1404 */1405static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {1406	.has_reset		= true,1407	.pcm_formats		= SUN4I_FORMATS_A10,1408	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,1409	.sun4i_i2s_regmap	= &sun4i_i2s_regmap_config,1410	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),1411	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),1412	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),1413	.bclk_dividers		= sun4i_i2s_bclk_div,1414	.num_bclk_dividers	= ARRAY_SIZE(sun4i_i2s_bclk_div),1415	.mclk_dividers		= sun4i_i2s_mclk_div,1416	.num_mclk_dividers	= ARRAY_SIZE(sun4i_i2s_mclk_div),1417	.get_bclk_parent_rate	= sun4i_i2s_get_bclk_parent_rate,1418	.get_sr			= sun4i_i2s_get_sr,1419	.get_wss		= sun4i_i2s_get_wss,1420	.set_chan_cfg		= sun4i_i2s_set_chan_cfg,1421	.set_fmt		= sun4i_i2s_set_soc_fmt,1422};1423 1424static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {1425	.has_reset		= true,1426	.pcm_formats		= SUN4I_FORMATS_H3,1427	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,1428	.sun4i_i2s_regmap	= &sun8i_i2s_regmap_config,1429	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),1430	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),1431	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),1432	.bclk_dividers		= sun8i_i2s_clk_div,1433	.num_bclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),1434	.mclk_dividers		= sun8i_i2s_clk_div,1435	.num_mclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),1436	.get_bclk_parent_rate	= sun8i_i2s_get_bclk_parent_rate,1437	.get_sr			= sun8i_i2s_get_sr_wss,1438	.get_wss		= sun8i_i2s_get_sr_wss,1439	.set_chan_cfg		= sun8i_i2s_set_chan_cfg,1440	.set_fmt		= sun8i_i2s_set_soc_fmt,1441};1442 1443static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {1444	.has_reset		= true,1445	.pcm_formats		= SUN4I_FORMATS_H3,1446	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,1447	.sun4i_i2s_regmap	= &sun4i_i2s_regmap_config,1448	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),1449	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),1450	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),1451	.bclk_dividers		= sun4i_i2s_bclk_div,1452	.num_bclk_dividers	= ARRAY_SIZE(sun4i_i2s_bclk_div),1453	.mclk_dividers		= sun4i_i2s_mclk_div,1454	.num_mclk_dividers	= ARRAY_SIZE(sun4i_i2s_mclk_div),1455	.get_bclk_parent_rate	= sun4i_i2s_get_bclk_parent_rate,1456	.get_sr			= sun4i_i2s_get_sr,1457	.get_wss		= sun4i_i2s_get_wss,1458	.set_chan_cfg		= sun4i_i2s_set_chan_cfg,1459	.set_fmt		= sun4i_i2s_set_soc_fmt,1460};1461 1462static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = {1463	.has_reset		= true,1464	.pcm_formats		= SUN4I_FORMATS_H3,1465	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,1466	.sun4i_i2s_regmap	= &sun50i_h6_i2s_regmap_config,1467	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),1468	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),1469	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),1470	.bclk_dividers		= sun8i_i2s_clk_div,1471	.num_bclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),1472	.mclk_dividers		= sun8i_i2s_clk_div,1473	.num_mclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),1474	.get_bclk_parent_rate	= sun8i_i2s_get_bclk_parent_rate,1475	.get_sr			= sun8i_i2s_get_sr_wss,1476	.get_wss		= sun8i_i2s_get_sr_wss,1477	.set_chan_cfg		= sun50i_h6_i2s_set_chan_cfg,1478	.set_fmt		= sun50i_h6_i2s_set_soc_fmt,1479};1480 1481static const struct sun4i_i2s_quirks sun50i_r329_i2s_quirks = {1482	.has_reset		= true,1483	.pcm_formats		= SUN4I_FORMATS_H3,1484	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,1485	.sun4i_i2s_regmap	= &sun50i_h6_i2s_regmap_config,1486	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),1487	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),1488	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),1489	.num_din_pins		= 4,1490	.num_dout_pins		= 4,1491	.bclk_dividers		= sun8i_i2s_clk_div,1492	.num_bclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),1493	.mclk_dividers		= sun8i_i2s_clk_div,1494	.num_mclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),1495	.get_bclk_parent_rate	= sun8i_i2s_get_bclk_parent_rate,1496	.get_sr			= sun8i_i2s_get_sr_wss,1497	.get_wss		= sun8i_i2s_get_sr_wss,1498	.set_chan_cfg		= sun50i_h6_i2s_set_chan_cfg,1499	.set_fmt		= sun50i_h6_i2s_set_soc_fmt,1500};1501 1502static int sun4i_i2s_init_regmap_fields(struct device *dev,1503					struct sun4i_i2s *i2s)1504{1505	i2s->field_clkdiv_mclk_en =1506		devm_regmap_field_alloc(dev, i2s->regmap,1507					i2s->variant->field_clkdiv_mclk_en);1508	if (IS_ERR(i2s->field_clkdiv_mclk_en))1509		return PTR_ERR(i2s->field_clkdiv_mclk_en);1510 1511	i2s->field_fmt_wss =1512			devm_regmap_field_alloc(dev, i2s->regmap,1513						i2s->variant->field_fmt_wss);1514	if (IS_ERR(i2s->field_fmt_wss))1515		return PTR_ERR(i2s->field_fmt_wss);1516 1517	i2s->field_fmt_sr =1518			devm_regmap_field_alloc(dev, i2s->regmap,1519						i2s->variant->field_fmt_sr);1520	if (IS_ERR(i2s->field_fmt_sr))1521		return PTR_ERR(i2s->field_fmt_sr);1522 1523	return 0;1524}1525 1526static int sun4i_i2s_probe(struct platform_device *pdev)1527{1528	struct sun4i_i2s *i2s;1529	struct resource *res;1530	void __iomem *regs;1531	int irq, ret;1532 1533	i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);1534	if (!i2s)1535		return -ENOMEM;1536	platform_set_drvdata(pdev, i2s);1537 1538	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);1539	if (IS_ERR(regs))1540		return PTR_ERR(regs);1541 1542	irq = platform_get_irq(pdev, 0);1543	if (irq < 0)1544		return irq;1545 1546	i2s->variant = of_device_get_match_data(&pdev->dev);1547	if (!i2s->variant) {1548		dev_err(&pdev->dev, "Failed to determine the quirks to use\n");1549		return -ENODEV;1550	}1551 1552	i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");1553	if (IS_ERR(i2s->bus_clk)) {1554		dev_err(&pdev->dev, "Can't get our bus clock\n");1555		return PTR_ERR(i2s->bus_clk);1556	}1557 1558	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,1559					    i2s->variant->sun4i_i2s_regmap);1560	if (IS_ERR(i2s->regmap)) {1561		dev_err(&pdev->dev, "Regmap initialisation failed\n");1562		return PTR_ERR(i2s->regmap);1563	}1564 1565	i2s->mod_clk = devm_clk_get(&pdev->dev, "mod");1566	if (IS_ERR(i2s->mod_clk)) {1567		dev_err(&pdev->dev, "Can't get our mod clock\n");1568		return PTR_ERR(i2s->mod_clk);1569	}1570 1571	if (i2s->variant->has_reset) {1572		i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);1573		if (IS_ERR(i2s->rst)) {1574			dev_err(&pdev->dev, "Failed to get reset control\n");1575			return PTR_ERR(i2s->rst);1576		}1577	}1578 1579	if (!IS_ERR(i2s->rst)) {1580		ret = reset_control_deassert(i2s->rst);1581		if (ret) {1582			dev_err(&pdev->dev,1583				"Failed to deassert the reset control\n");1584			return -EINVAL;1585		}1586	}1587 1588	i2s->playback_dma_data.addr = res->start +1589					i2s->variant->reg_offset_txdata;1590	i2s->playback_dma_data.maxburst = 8;1591 1592	i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;1593	i2s->capture_dma_data.maxburst = 8;1594 1595	pm_runtime_enable(&pdev->dev);1596	if (!pm_runtime_enabled(&pdev->dev)) {1597		ret = sun4i_i2s_runtime_resume(&pdev->dev);1598		if (ret)1599			goto err_pm_disable;1600	}1601 1602	ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s);1603	if (ret) {1604		dev_err(&pdev->dev, "Could not initialise regmap fields\n");1605		goto err_suspend;1606	}1607 1608	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);1609	if (ret) {1610		dev_err(&pdev->dev, "Could not register PCM\n");1611		goto err_suspend;1612	}1613 1614	ret = devm_snd_soc_register_component(&pdev->dev,1615					      &sun4i_i2s_component,1616					      &sun4i_i2s_dai, 1);1617	if (ret) {1618		dev_err(&pdev->dev, "Could not register DAI\n");1619		goto err_suspend;1620	}1621 1622	return 0;1623 1624err_suspend:1625	if (!pm_runtime_status_suspended(&pdev->dev))1626		sun4i_i2s_runtime_suspend(&pdev->dev);1627err_pm_disable:1628	pm_runtime_disable(&pdev->dev);1629	if (!IS_ERR(i2s->rst))1630		reset_control_assert(i2s->rst);1631 1632	return ret;1633}1634 1635static void sun4i_i2s_remove(struct platform_device *pdev)1636{1637	struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev);1638 1639	pm_runtime_disable(&pdev->dev);1640	if (!pm_runtime_status_suspended(&pdev->dev))1641		sun4i_i2s_runtime_suspend(&pdev->dev);1642 1643	if (!IS_ERR(i2s->rst))1644		reset_control_assert(i2s->rst);1645}1646 1647static const struct of_device_id sun4i_i2s_match[] = {1648	{1649		.compatible = "allwinner,sun4i-a10-i2s",1650		.data = &sun4i_a10_i2s_quirks,1651	},1652	{1653		.compatible = "allwinner,sun6i-a31-i2s",1654		.data = &sun6i_a31_i2s_quirks,1655	},1656	{1657		.compatible = "allwinner,sun8i-a83t-i2s",1658		.data = &sun8i_a83t_i2s_quirks,1659	},1660	{1661		.compatible = "allwinner,sun8i-h3-i2s",1662		.data = &sun8i_h3_i2s_quirks,1663	},1664	{1665		.compatible = "allwinner,sun50i-a64-codec-i2s",1666		.data = &sun50i_a64_codec_i2s_quirks,1667	},1668	{1669		.compatible = "allwinner,sun50i-h6-i2s",1670		.data = &sun50i_h6_i2s_quirks,1671	},1672	{1673		.compatible = "allwinner,sun50i-r329-i2s",1674		.data = &sun50i_r329_i2s_quirks,1675	},1676	{}1677};1678MODULE_DEVICE_TABLE(of, sun4i_i2s_match);1679 1680static const struct dev_pm_ops sun4i_i2s_pm_ops = {1681	.runtime_resume		= sun4i_i2s_runtime_resume,1682	.runtime_suspend	= sun4i_i2s_runtime_suspend,1683};1684 1685static struct platform_driver sun4i_i2s_driver = {1686	.probe	= sun4i_i2s_probe,1687	.remove = sun4i_i2s_remove,1688	.driver	= {1689		.name		= "sun4i-i2s",1690		.of_match_table	= sun4i_i2s_match,1691		.pm		= &sun4i_i2s_pm_ops,1692	},1693};1694module_platform_driver(sun4i_i2s_driver);1695 1696MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");1697MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");1698MODULE_DESCRIPTION("Allwinner A10 I2S driver");1699MODULE_LICENSE("GPL");1700