xref: /openbmc/linux/sound/soc/sunxi/sun4i-i2s.c (revision ca2478a7d974f38d29d27acb42a952c7f168916e)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fa7c0d13SMaxime Ripard /*
3fa7c0d13SMaxime Ripard  * Copyright (C) 2015 Andrea Venturi
4fa7c0d13SMaxime Ripard  * Andrea Venturi <be17068@iperbole.bo.it>
5fa7c0d13SMaxime Ripard  *
6fa7c0d13SMaxime Ripard  * Copyright (C) 2016 Maxime Ripard
7fa7c0d13SMaxime Ripard  * Maxime Ripard <maxime.ripard@free-electrons.com>
8fa7c0d13SMaxime Ripard  */
9fa7c0d13SMaxime Ripard 
10fa7c0d13SMaxime Ripard #include <linux/clk.h>
11fa7c0d13SMaxime Ripard #include <linux/dmaengine.h>
12fa7c0d13SMaxime Ripard #include <linux/module.h>
132ad6f30dSMylène Josserand #include <linux/of_device.h>
14fa7c0d13SMaxime Ripard #include <linux/platform_device.h>
15fa7c0d13SMaxime Ripard #include <linux/pm_runtime.h>
16fa7c0d13SMaxime Ripard #include <linux/regmap.h>
172ad6f30dSMylène Josserand #include <linux/reset.h>
18fa7c0d13SMaxime Ripard 
19fa7c0d13SMaxime Ripard #include <sound/dmaengine_pcm.h>
20fa7c0d13SMaxime Ripard #include <sound/pcm_params.h>
21fa7c0d13SMaxime Ripard #include <sound/soc.h>
22fa7c0d13SMaxime Ripard #include <sound/soc-dai.h>
23fa7c0d13SMaxime Ripard 
24fa7c0d13SMaxime Ripard #define SUN4I_I2S_CTRL_REG		0x00
25fa7c0d13SMaxime Ripard #define SUN4I_I2S_CTRL_SDO_EN_MASK		GENMASK(11, 8)
26fa7c0d13SMaxime Ripard #define SUN4I_I2S_CTRL_SDO_EN(sdo)			BIT(8 + (sdo))
27fa7c0d13SMaxime Ripard #define SUN4I_I2S_CTRL_MODE_MASK		BIT(5)
28fa7c0d13SMaxime Ripard #define SUN4I_I2S_CTRL_MODE_SLAVE			(1 << 5)
29fa7c0d13SMaxime Ripard #define SUN4I_I2S_CTRL_MODE_MASTER			(0 << 5)
30fa7c0d13SMaxime Ripard #define SUN4I_I2S_CTRL_TX_EN			BIT(2)
31fa7c0d13SMaxime Ripard #define SUN4I_I2S_CTRL_RX_EN			BIT(1)
32fa7c0d13SMaxime Ripard #define SUN4I_I2S_CTRL_GL_EN			BIT(0)
33fa7c0d13SMaxime Ripard 
34fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_REG		0x04
35fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK	BIT(7)
36fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED		(1 << 7)
37fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL		(0 << 7)
38fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK	BIT(6)
39fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED		(1 << 6)
40fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL		(0 << 6)
41fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_SR_MASK			GENMASK(5, 4)
42fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_SR(sr)				((sr) << 4)
43fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_WSS_MASK			GENMASK(3, 2)
44fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_WSS(wss)				((wss) << 2)
45fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_FMT_MASK			GENMASK(1, 0)
46fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_FMT_RIGHT_J			(2 << 0)
47fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_FMT_LEFT_J			(1 << 0)
48fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT0_FMT_I2S				(0 << 0)
49fa7c0d13SMaxime Ripard 
50fa7c0d13SMaxime Ripard #define SUN4I_I2S_FMT1_REG		0x08
51d8659dd9SMarcus Cooper #define SUN4I_I2S_FMT1_REG_SEXT_MASK		BIT(8)
52d8659dd9SMarcus Cooper #define SUN4I_I2S_FMT1_REG_SEXT(sext)			((sext) << 8)
53d8659dd9SMarcus Cooper 
54fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_TX_REG		0x0c
55fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_RX_REG		0x10
56fa7c0d13SMaxime Ripard 
57fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_CTRL_REG		0x14
58fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_CTRL_FLUSH_TX		BIT(25)
59fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_CTRL_FLUSH_RX		BIT(24)
60fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK	BIT(2)
61fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_CTRL_TX_MODE(mode)		((mode) << 2)
62fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK	GENMASK(1, 0)
63fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_CTRL_RX_MODE(mode)		(mode)
64fa7c0d13SMaxime Ripard 
65fa7c0d13SMaxime Ripard #define SUN4I_I2S_FIFO_STA_REG		0x18
66fa7c0d13SMaxime Ripard 
67fa7c0d13SMaxime Ripard #define SUN4I_I2S_DMA_INT_CTRL_REG	0x1c
68fa7c0d13SMaxime Ripard #define SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN	BIT(7)
69fa7c0d13SMaxime Ripard #define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN	BIT(3)
70fa7c0d13SMaxime Ripard 
71fa7c0d13SMaxime Ripard #define SUN4I_I2S_INT_STA_REG		0x20
72fa7c0d13SMaxime Ripard 
73fa7c0d13SMaxime Ripard #define SUN4I_I2S_CLK_DIV_REG		0x24
74fa7c0d13SMaxime Ripard #define SUN4I_I2S_CLK_DIV_MCLK_EN		BIT(7)
75fa7c0d13SMaxime Ripard #define SUN4I_I2S_CLK_DIV_BCLK_MASK		GENMASK(6, 4)
76fa7c0d13SMaxime Ripard #define SUN4I_I2S_CLK_DIV_BCLK(bclk)			((bclk) << 4)
77fa7c0d13SMaxime Ripard #define SUN4I_I2S_CLK_DIV_MCLK_MASK		GENMASK(3, 0)
78fa7c0d13SMaxime Ripard #define SUN4I_I2S_CLK_DIV_MCLK(mclk)			((mclk) << 0)
79fa7c0d13SMaxime Ripard 
80cf2c0e1cSMaxime Ripard #define SUN4I_I2S_TX_CNT_REG		0x28
81cf2c0e1cSMaxime Ripard #define SUN4I_I2S_RX_CNT_REG		0x2c
82fa7c0d13SMaxime Ripard 
83fa7c0d13SMaxime Ripard #define SUN4I_I2S_TX_CHAN_SEL_REG	0x30
84d70be625SMaxime Ripard #define SUN4I_I2S_CHAN_SEL_MASK			GENMASK(2, 0)
856eb4f274SMarcus Cooper #define SUN4I_I2S_CHAN_SEL(num_chan)		(((num_chan) - 1) << 0)
86fa7c0d13SMaxime Ripard 
87fa7c0d13SMaxime Ripard #define SUN4I_I2S_TX_CHAN_MAP_REG	0x34
88fa7c0d13SMaxime Ripard #define SUN4I_I2S_TX_CHAN_MAP(chan, sample)	((sample) << (chan << 2))
89fa7c0d13SMaxime Ripard 
90fa7c0d13SMaxime Ripard #define SUN4I_I2S_RX_CHAN_SEL_REG	0x38
91fa7c0d13SMaxime Ripard #define SUN4I_I2S_RX_CHAN_MAP_REG	0x3c
92fa7c0d13SMaxime Ripard 
937d299381SMarcus Cooper /* Defines required for sun8i-h3 support */
947d299381SMarcus Cooper #define SUN8I_I2S_CTRL_BCLK_OUT			BIT(18)
957d299381SMarcus Cooper #define SUN8I_I2S_CTRL_LRCK_OUT			BIT(17)
967d299381SMarcus Cooper 
9771137bcdSMaxime Ripard #define SUN8I_I2S_CTRL_MODE_MASK		GENMASK(5, 4)
9871137bcdSMaxime Ripard #define SUN8I_I2S_CTRL_MODE_RIGHT		(2 << 4)
9971137bcdSMaxime Ripard #define SUN8I_I2S_CTRL_MODE_LEFT		(1 << 4)
10071137bcdSMaxime Ripard #define SUN8I_I2S_CTRL_MODE_PCM			(0 << 4)
10171137bcdSMaxime Ripard 
102515fcfbcSMaxime Ripard #define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK	BIT(19)
103*b9bb9634SMatteo Martelli #define SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH	(1 << 19)
104*b9bb9634SMatteo Martelli #define SUN8I_I2S_FMT0_LRCLK_POLARITY_START_LOW		(0 << 19)
1057d299381SMarcus Cooper #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK		GENMASK(17, 8)
1067d299381SMarcus Cooper #define SUN8I_I2S_FMT0_LRCK_PERIOD(period)	((period - 1) << 8)
107515fcfbcSMaxime Ripard #define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK	BIT(7)
108515fcfbcSMaxime Ripard #define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED		(1 << 7)
109515fcfbcSMaxime Ripard #define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL		(0 << 7)
1107d299381SMarcus Cooper 
111d8659dd9SMarcus Cooper #define SUN8I_I2S_FMT1_REG_SEXT_MASK		GENMASK(5, 4)
112d8659dd9SMarcus Cooper #define SUN8I_I2S_FMT1_REG_SEXT(sext)			((sext) << 4)
113d8659dd9SMarcus Cooper 
1147d299381SMarcus Cooper #define SUN8I_I2S_INT_STA_REG		0x0c
1157d299381SMarcus Cooper #define SUN8I_I2S_FIFO_TX_REG		0x20
1167d299381SMarcus Cooper 
1177d299381SMarcus Cooper #define SUN8I_I2S_CHAN_CFG_REG		0x30
118c8bbc1deSSamuel Holland #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK	GENMASK(7, 4)
1195a338679SYong Deng #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)	((chan - 1) << 4)
120c8bbc1deSSamuel Holland #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK	GENMASK(3, 0)
1217d299381SMarcus Cooper #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan)	(chan - 1)
1227d299381SMarcus Cooper 
1237d299381SMarcus Cooper #define SUN8I_I2S_TX_CHAN_MAP_REG	0x44
1247d299381SMarcus Cooper #define SUN8I_I2S_TX_CHAN_SEL_REG	0x34
1257e46169aSMarcus Cooper #define SUN8I_I2S_TX_CHAN_OFFSET_MASK		GENMASK(13, 12)
1267d299381SMarcus Cooper #define SUN8I_I2S_TX_CHAN_OFFSET(offset)	(offset << 12)
1277d299381SMarcus Cooper #define SUN8I_I2S_TX_CHAN_EN_MASK		GENMASK(11, 4)
1287d299381SMarcus Cooper #define SUN8I_I2S_TX_CHAN_EN(num_chan)		(((1 << num_chan) - 1) << 4)
1297d299381SMarcus Cooper 
1307d299381SMarcus Cooper #define SUN8I_I2S_RX_CHAN_SEL_REG	0x54
1317d299381SMarcus Cooper #define SUN8I_I2S_RX_CHAN_MAP_REG	0x58
1327d299381SMarcus Cooper 
13373adf87bSJernej Skrabec /* Defines required for sun50i-h6 support */
13473adf87bSJernej Skrabec #define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK	GENMASK(21, 20)
13573adf87bSJernej Skrabec #define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)	((offset) << 20)
13673adf87bSJernej Skrabec #define SUN50I_H6_I2S_TX_CHAN_SEL_MASK		GENMASK(19, 16)
13773adf87bSJernej Skrabec #define SUN50I_H6_I2S_TX_CHAN_SEL(chan)		((chan - 1) << 16)
13873adf87bSJernej Skrabec #define SUN50I_H6_I2S_TX_CHAN_EN_MASK		GENMASK(15, 0)
13973adf87bSJernej Skrabec #define SUN50I_H6_I2S_TX_CHAN_EN(num_chan)	(((1 << num_chan) - 1))
14073adf87bSJernej Skrabec 
141c8bbc1deSSamuel Holland #define SUN50I_H6_I2S_TX_CHAN_SEL_REG(pin)	(0x34 + 4 * (pin))
142c8bbc1deSSamuel Holland #define SUN50I_H6_I2S_TX_CHAN_MAP0_REG(pin)	(0x44 + 8 * (pin))
143c8bbc1deSSamuel Holland #define SUN50I_H6_I2S_TX_CHAN_MAP1_REG(pin)	(0x48 + 8 * (pin))
14473adf87bSJernej Skrabec 
14573adf87bSJernej Skrabec #define SUN50I_H6_I2S_RX_CHAN_SEL_REG	0x64
14673adf87bSJernej Skrabec #define SUN50I_H6_I2S_RX_CHAN_MAP0_REG	0x68
14773adf87bSJernej Skrabec #define SUN50I_H6_I2S_RX_CHAN_MAP1_REG	0x6C
14873adf87bSJernej Skrabec 
149c8bbc1deSSamuel Holland #define SUN50I_R329_I2S_RX_CHAN_MAP0_REG 0x68
150c8bbc1deSSamuel Holland #define SUN50I_R329_I2S_RX_CHAN_MAP1_REG 0x6c
151c8bbc1deSSamuel Holland #define SUN50I_R329_I2S_RX_CHAN_MAP2_REG 0x70
152c8bbc1deSSamuel Holland #define SUN50I_R329_I2S_RX_CHAN_MAP3_REG 0x74
153c8bbc1deSSamuel Holland 
154619c15f7SMaxime Ripard struct sun4i_i2s;
155619c15f7SMaxime Ripard 
15647bea0c8SMarcus Cooper /**
15747bea0c8SMarcus Cooper  * struct sun4i_i2s_quirks - Differences between SoC variants.
15847bea0c8SMarcus Cooper  * @has_reset: SoC needs reset deasserted.
1593509476eSMarcus Cooper  * @reg_offset_txdata: offset of the tx fifo.
160cd1c63dfSMarcus Cooper  * @sun4i_i2s_regmap: regmap config to use.
1615f93b063SMarcus Cooper  * @field_clkdiv_mclk_en: regmap field to enable mclk output.
16277164715SMarcus Cooper  * @field_fmt_wss: regmap field to set word select size.
16377164715SMarcus Cooper  * @field_fmt_sr: regmap field to set sample resolution.
1647c619b30SPierre-Louis Bossart  * @num_din_pins: input pins
1657c619b30SPierre-Louis Bossart  * @num_dout_pins: output pins (currently set but unused)
166643e305eSPierre-Louis Bossart  * @bclk_dividers: bit clock dividers array
167643e305eSPierre-Louis Bossart  * @num_bclk_dividers: number of bit clock dividers
168643e305eSPierre-Louis Bossart  * @mclk_dividers: mclk dividers array
169643e305eSPierre-Louis Bossart  * @num_mclk_dividers: number of mclk dividers
170643e305eSPierre-Louis Bossart  * @get_bclk_parent_rate: callback to get bclk parent rate
171643e305eSPierre-Louis Bossart  * @get_sr: callback to get sample resolution
172643e305eSPierre-Louis Bossart  * @get_wss: callback to get word select size
173643e305eSPierre-Louis Bossart  * @set_chan_cfg: callback to set channel configuration
174643e305eSPierre-Louis Bossart  * @set_fmt: callback to set format
17547bea0c8SMarcus Cooper  */
17647bea0c8SMarcus Cooper struct sun4i_i2s_quirks {
17747bea0c8SMarcus Cooper 	bool				has_reset;
1783509476eSMarcus Cooper 	unsigned int			reg_offset_txdata;	/* TX FIFO */
179cd1c63dfSMarcus Cooper 	const struct regmap_config	*sun4i_i2s_regmap;
1806eb4f274SMarcus Cooper 
1816eb4f274SMarcus Cooper 	/* Register fields for i2s */
1825f93b063SMarcus Cooper 	struct reg_field		field_clkdiv_mclk_en;
18377164715SMarcus Cooper 	struct reg_field		field_fmt_wss;
18477164715SMarcus Cooper 	struct reg_field		field_fmt_sr;
185619c15f7SMaxime Ripard 
186e2ce580fSSamuel Holland 	unsigned int			num_din_pins;
187e2ce580fSSamuel Holland 	unsigned int			num_dout_pins;
188e2ce580fSSamuel Holland 
189c1d3a921SMaxime Ripard 	const struct sun4i_i2s_clk_div	*bclk_dividers;
190c1d3a921SMaxime Ripard 	unsigned int			num_bclk_dividers;
191c1d3a921SMaxime Ripard 	const struct sun4i_i2s_clk_div	*mclk_dividers;
192c1d3a921SMaxime Ripard 	unsigned int			num_mclk_dividers;
193c1d3a921SMaxime Ripard 
19408c7b7d5SClément Péron 	unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *i2s);
1959c2d255fSClément Péron 	int	(*get_sr)(unsigned int width);
1969c2d255fSClément Péron 	int	(*get_wss)(unsigned int width);
197c779e2deSClément Péron 
198c779e2deSClément Péron 	/*
199c779e2deSClément Péron 	 * In the set_chan_cfg() function pointer:
200c779e2deSClément Péron 	 * @slots: channels per frame + padding slots, regardless of format
201c779e2deSClément Péron 	 * @slot_width: bits per sample + padding bits, regardless of format
202c779e2deSClément Péron 	 */
203c779e2deSClément Péron 	int	(*set_chan_cfg)(const struct sun4i_i2s *i2s,
204c779e2deSClément Péron 				unsigned int channels,	unsigned int slots,
205c779e2deSClément Péron 				unsigned int slot_width);
20608c7b7d5SClément Péron 	int	(*set_fmt)(const struct sun4i_i2s *i2s, unsigned int fmt);
20747bea0c8SMarcus Cooper };
20847bea0c8SMarcus Cooper 
209fa7c0d13SMaxime Ripard struct sun4i_i2s {
210fa7c0d13SMaxime Ripard 	struct clk	*bus_clk;
211fa7c0d13SMaxime Ripard 	struct clk	*mod_clk;
212fa7c0d13SMaxime Ripard 	struct regmap	*regmap;
2132ad6f30dSMylène Josserand 	struct reset_control *rst;
214fa7c0d13SMaxime Ripard 
2157ae7834eSMaxime Ripard 	unsigned int	format;
216b2b7b56fSMaxime Ripard 	unsigned int	mclk_freq;
217137befe1SMaxime Ripard 	unsigned int	slots;
218137befe1SMaxime Ripard 	unsigned int	slot_width;
219b2b7b56fSMaxime Ripard 
220ae73b34fSMaxime Ripard 	struct snd_dmaengine_dai_dma_data	capture_dma_data;
221fa7c0d13SMaxime Ripard 	struct snd_dmaengine_dai_dma_data	playback_dma_data;
22247bea0c8SMarcus Cooper 
2236eb4f274SMarcus Cooper 	/* Register fields for i2s */
2245f93b063SMarcus Cooper 	struct regmap_field	*field_clkdiv_mclk_en;
22577164715SMarcus Cooper 	struct regmap_field	*field_fmt_wss;
22677164715SMarcus Cooper 	struct regmap_field	*field_fmt_sr;
2276eb4f274SMarcus Cooper 
22847bea0c8SMarcus Cooper 	const struct sun4i_i2s_quirks	*variant;
229fa7c0d13SMaxime Ripard };
230fa7c0d13SMaxime Ripard 
231fa7c0d13SMaxime Ripard struct sun4i_i2s_clk_div {
232fa7c0d13SMaxime Ripard 	u8	div;
233fa7c0d13SMaxime Ripard 	u8	val;
234fa7c0d13SMaxime Ripard };
235fa7c0d13SMaxime Ripard 
236fa7c0d13SMaxime Ripard static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = {
237fa7c0d13SMaxime Ripard 	{ .div = 2, .val = 0 },
238fa7c0d13SMaxime Ripard 	{ .div = 4, .val = 1 },
239fa7c0d13SMaxime Ripard 	{ .div = 6, .val = 2 },
240fa7c0d13SMaxime Ripard 	{ .div = 8, .val = 3 },
241fa7c0d13SMaxime Ripard 	{ .div = 12, .val = 4 },
242fa7c0d13SMaxime Ripard 	{ .div = 16, .val = 5 },
2437d299381SMarcus Cooper 	/* TODO - extend divide ratio supported by newer SoCs */
244fa7c0d13SMaxime Ripard };
245fa7c0d13SMaxime Ripard 
246fa7c0d13SMaxime Ripard static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
247fa7c0d13SMaxime Ripard 	{ .div = 1, .val = 0 },
248fa7c0d13SMaxime Ripard 	{ .div = 2, .val = 1 },
249fa7c0d13SMaxime Ripard 	{ .div = 4, .val = 2 },
250fa7c0d13SMaxime Ripard 	{ .div = 6, .val = 3 },
251fa7c0d13SMaxime Ripard 	{ .div = 8, .val = 4 },
252fa7c0d13SMaxime Ripard 	{ .div = 12, .val = 5 },
253fa7c0d13SMaxime Ripard 	{ .div = 16, .val = 6 },
254fa7c0d13SMaxime Ripard 	{ .div = 24, .val = 7 },
2557d299381SMarcus Cooper 	/* TODO - extend divide ratio supported by newer SoCs */
256fa7c0d13SMaxime Ripard };
257fa7c0d13SMaxime Ripard 
258c1d3a921SMaxime Ripard static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = {
259c1d3a921SMaxime Ripard 	{ .div = 1, .val = 1 },
260c1d3a921SMaxime Ripard 	{ .div = 2, .val = 2 },
261c1d3a921SMaxime Ripard 	{ .div = 4, .val = 3 },
262c1d3a921SMaxime Ripard 	{ .div = 6, .val = 4 },
263c1d3a921SMaxime Ripard 	{ .div = 8, .val = 5 },
264c1d3a921SMaxime Ripard 	{ .div = 12, .val = 6 },
265c1d3a921SMaxime Ripard 	{ .div = 16, .val = 7 },
266c1d3a921SMaxime Ripard 	{ .div = 24, .val = 8 },
267c1d3a921SMaxime Ripard 	{ .div = 32, .val = 9 },
268c1d3a921SMaxime Ripard 	{ .div = 48, .val = 10 },
269c1d3a921SMaxime Ripard 	{ .div = 64, .val = 11 },
270c1d3a921SMaxime Ripard 	{ .div = 96, .val = 12 },
271c1d3a921SMaxime Ripard 	{ .div = 128, .val = 13 },
272c1d3a921SMaxime Ripard 	{ .div = 176, .val = 14 },
273c1d3a921SMaxime Ripard 	{ .div = 192, .val = 15 },
274c1d3a921SMaxime Ripard };
275c1d3a921SMaxime Ripard 
sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s * i2s)276fb19739dSMaxime Ripard static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
277fb19739dSMaxime Ripard {
278fb19739dSMaxime Ripard 	return i2s->mclk_freq;
279fb19739dSMaxime Ripard }
280fb19739dSMaxime Ripard 
sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s * i2s)281fb19739dSMaxime Ripard static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s)
282fb19739dSMaxime Ripard {
283fb19739dSMaxime Ripard 	return clk_get_rate(i2s->mod_clk);
284fb19739dSMaxime Ripard }
285fb19739dSMaxime Ripard 
sun4i_i2s_get_bclk_div(struct sun4i_i2s * i2s,unsigned long parent_rate,unsigned int sampling_rate,unsigned int channels,unsigned int word_size)286fa7c0d13SMaxime Ripard static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
2877df8f9a2SMaxime Ripard 				  unsigned long parent_rate,
2887df8f9a2SMaxime Ripard 				  unsigned int sampling_rate,
2890083a507SMaxime Ripard 				  unsigned int channels,
290fa7c0d13SMaxime Ripard 				  unsigned int word_size)
291fa7c0d13SMaxime Ripard {
292c1d3a921SMaxime Ripard 	const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers;
2930083a507SMaxime Ripard 	int div = parent_rate / sampling_rate / word_size / channels;
294fa7c0d13SMaxime Ripard 	int i;
295fa7c0d13SMaxime Ripard 
296c1d3a921SMaxime Ripard 	for (i = 0; i < i2s->variant->num_bclk_dividers; i++) {
297c1d3a921SMaxime Ripard 		const struct sun4i_i2s_clk_div *bdiv = &dividers[i];
298fa7c0d13SMaxime Ripard 
299fa7c0d13SMaxime Ripard 		if (bdiv->div == div)
300fa7c0d13SMaxime Ripard 			return bdiv->val;
301fa7c0d13SMaxime Ripard 	}
302fa7c0d13SMaxime Ripard 
303fa7c0d13SMaxime Ripard 	return -EINVAL;
304fa7c0d13SMaxime Ripard }
305fa7c0d13SMaxime Ripard 
sun4i_i2s_get_mclk_div(struct sun4i_i2s * i2s,unsigned long parent_rate,unsigned long mclk_rate)306fa7c0d13SMaxime Ripard static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
3078bcf62b7SMaxime Ripard 				  unsigned long parent_rate,
3088bcf62b7SMaxime Ripard 				  unsigned long mclk_rate)
309fa7c0d13SMaxime Ripard {
310c1d3a921SMaxime Ripard 	const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers;
3118bcf62b7SMaxime Ripard 	int div = parent_rate / mclk_rate;
312fa7c0d13SMaxime Ripard 	int i;
313fa7c0d13SMaxime Ripard 
314c1d3a921SMaxime Ripard 	for (i = 0; i < i2s->variant->num_mclk_dividers; i++) {
315c1d3a921SMaxime Ripard 		const struct sun4i_i2s_clk_div *mdiv = &dividers[i];
316fa7c0d13SMaxime Ripard 
317fa7c0d13SMaxime Ripard 		if (mdiv->div == div)
318fa7c0d13SMaxime Ripard 			return mdiv->val;
319fa7c0d13SMaxime Ripard 	}
320fa7c0d13SMaxime Ripard 
321fa7c0d13SMaxime Ripard 	return -EINVAL;
322fa7c0d13SMaxime Ripard }
323fa7c0d13SMaxime Ripard 
324fa7c0d13SMaxime Ripard static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 };
sun4i_i2s_oversample_is_valid(unsigned int oversample)325b2b7b56fSMaxime Ripard static bool sun4i_i2s_oversample_is_valid(unsigned int oversample)
326b2b7b56fSMaxime Ripard {
327b2b7b56fSMaxime Ripard 	int i;
328b2b7b56fSMaxime Ripard 
329b2b7b56fSMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++)
330b2b7b56fSMaxime Ripard 		if (sun4i_i2s_oversample_rates[i] == oversample)
331b2b7b56fSMaxime Ripard 			return true;
332b2b7b56fSMaxime Ripard 
333b2b7b56fSMaxime Ripard 	return false;
334b2b7b56fSMaxime Ripard }
335fa7c0d13SMaxime Ripard 
sun4i_i2s_set_clk_rate(struct snd_soc_dai * dai,unsigned int rate,unsigned int slots,unsigned int slot_width)3362ff739b9SChen-Yu Tsai static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
337fa7c0d13SMaxime Ripard 				  unsigned int rate,
338137befe1SMaxime Ripard 				  unsigned int slots,
3395389f476SMaxime Ripard 				  unsigned int slot_width)
340fa7c0d13SMaxime Ripard {
3412ff739b9SChen-Yu Tsai 	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
342fb19739dSMaxime Ripard 	unsigned int oversample_rate, clk_rate, bclk_parent_rate;
343fa7c0d13SMaxime Ripard 	int bclk_div, mclk_div;
344b2b7b56fSMaxime Ripard 	int ret;
345fa7c0d13SMaxime Ripard 
346fa7c0d13SMaxime Ripard 	switch (rate) {
347fa7c0d13SMaxime Ripard 	case 176400:
348fa7c0d13SMaxime Ripard 	case 88200:
349fa7c0d13SMaxime Ripard 	case 44100:
350fa7c0d13SMaxime Ripard 	case 22050:
351fa7c0d13SMaxime Ripard 	case 11025:
352fa7c0d13SMaxime Ripard 		clk_rate = 22579200;
353fa7c0d13SMaxime Ripard 		break;
354fa7c0d13SMaxime Ripard 
355fa7c0d13SMaxime Ripard 	case 192000:
356fa7c0d13SMaxime Ripard 	case 128000:
357fa7c0d13SMaxime Ripard 	case 96000:
358fa7c0d13SMaxime Ripard 	case 64000:
359fa7c0d13SMaxime Ripard 	case 48000:
360fa7c0d13SMaxime Ripard 	case 32000:
361fa7c0d13SMaxime Ripard 	case 24000:
362fa7c0d13SMaxime Ripard 	case 16000:
363fa7c0d13SMaxime Ripard 	case 12000:
364fa7c0d13SMaxime Ripard 	case 8000:
365fa7c0d13SMaxime Ripard 		clk_rate = 24576000;
366fa7c0d13SMaxime Ripard 		break;
367fa7c0d13SMaxime Ripard 
368fa7c0d13SMaxime Ripard 	default:
3692ff739b9SChen-Yu Tsai 		dev_err(dai->dev, "Unsupported sample rate: %u\n", rate);
370fa7c0d13SMaxime Ripard 		return -EINVAL;
371fa7c0d13SMaxime Ripard 	}
372fa7c0d13SMaxime Ripard 
373fa7c0d13SMaxime Ripard 	ret = clk_set_rate(i2s->mod_clk, clk_rate);
374fa7c0d13SMaxime Ripard 	if (ret)
375fa7c0d13SMaxime Ripard 		return ret;
376fa7c0d13SMaxime Ripard 
377b2b7b56fSMaxime Ripard 	oversample_rate = i2s->mclk_freq / rate;
3782ff739b9SChen-Yu Tsai 	if (!sun4i_i2s_oversample_is_valid(oversample_rate)) {
3792ff739b9SChen-Yu Tsai 		dev_err(dai->dev, "Unsupported oversample rate: %d\n",
3802ff739b9SChen-Yu Tsai 			oversample_rate);
381b2b7b56fSMaxime Ripard 		return -EINVAL;
3822ff739b9SChen-Yu Tsai 	}
383fa7c0d13SMaxime Ripard 
384fb19739dSMaxime Ripard 	bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);
385fb19739dSMaxime Ripard 	bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
3865389f476SMaxime Ripard 					  rate, slots, slot_width);
3872ff739b9SChen-Yu Tsai 	if (bclk_div < 0) {
3882ff739b9SChen-Yu Tsai 		dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
389b2b7b56fSMaxime Ripard 		return -EINVAL;
3902ff739b9SChen-Yu Tsai 	}
391b2b7b56fSMaxime Ripard 
3928bcf62b7SMaxime Ripard 	mclk_div = sun4i_i2s_get_mclk_div(i2s, clk_rate, i2s->mclk_freq);
3932ff739b9SChen-Yu Tsai 	if (mclk_div < 0) {
3942ff739b9SChen-Yu Tsai 		dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div);
395fa7c0d13SMaxime Ripard 		return -EINVAL;
3962ff739b9SChen-Yu Tsai 	}
397fa7c0d13SMaxime Ripard 
398fa7c0d13SMaxime Ripard 	regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
399fa7c0d13SMaxime Ripard 		     SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
4005f93b063SMarcus Cooper 		     SUN4I_I2S_CLK_DIV_MCLK(mclk_div));
4015f93b063SMarcus Cooper 
4025f93b063SMarcus Cooper 	regmap_field_write(i2s->field_clkdiv_mclk_en, 1);
403fa7c0d13SMaxime Ripard 
404fa7c0d13SMaxime Ripard 	return 0;
405fa7c0d13SMaxime Ripard }
406fa7c0d13SMaxime Ripard 
sun4i_i2s_get_sr(unsigned int width)4079c2d255fSClément Péron static int sun4i_i2s_get_sr(unsigned int width)
408619c15f7SMaxime Ripard {
4099c2d255fSClément Péron 	switch (width) {
4109c2d255fSClément Péron 	case 16:
4119c2d255fSClément Péron 		return 0;
4129c2d255fSClément Péron 	case 20:
4139c2d255fSClément Péron 		return 1;
4149c2d255fSClément Péron 	case 24:
4159c2d255fSClément Péron 		return 2;
416619c15f7SMaxime Ripard 	}
417619c15f7SMaxime Ripard 
418619c15f7SMaxime Ripard 	return -EINVAL;
419619c15f7SMaxime Ripard }
420619c15f7SMaxime Ripard 
sun4i_i2s_get_wss(unsigned int width)4219c2d255fSClément Péron static int sun4i_i2s_get_wss(unsigned int width)
422619c15f7SMaxime Ripard {
4239c2d255fSClément Péron 	switch (width) {
4249c2d255fSClément Péron 	case 16:
4259c2d255fSClément Péron 		return 0;
4269c2d255fSClément Péron 	case 20:
4279c2d255fSClément Péron 		return 1;
4289c2d255fSClément Péron 	case 24:
4299c2d255fSClément Péron 		return 2;
4309c2d255fSClément Péron 	case 32:
4319c2d255fSClément Péron 		return 3;
4329c2d255fSClément Péron 	}
433619c15f7SMaxime Ripard 
434619c15f7SMaxime Ripard 	return -EINVAL;
4359c2d255fSClément Péron }
436619c15f7SMaxime Ripard 
sun8i_i2s_get_sr_wss(unsigned int width)4379c2d255fSClément Péron static int sun8i_i2s_get_sr_wss(unsigned int width)
4389c2d255fSClément Péron {
4399c2d255fSClément Péron 	switch (width) {
4409c2d255fSClément Péron 	case 8:
4419c2d255fSClément Péron 		return 1;
4429c2d255fSClément Péron 	case 12:
4439c2d255fSClément Péron 		return 2;
4449c2d255fSClément Péron 	case 16:
4459c2d255fSClément Péron 		return 3;
4469c2d255fSClément Péron 	case 20:
4479c2d255fSClément Péron 		return 4;
4489c2d255fSClément Péron 	case 24:
4499c2d255fSClément Péron 		return 5;
4509c2d255fSClément Péron 	case 28:
4519c2d255fSClément Péron 		return 6;
4529c2d255fSClément Péron 	case 32:
4539c2d255fSClément Péron 		return 7;
4549c2d255fSClément Péron 	}
4559c2d255fSClément Péron 
4569c2d255fSClément Péron 	return -EINVAL;
457619c15f7SMaxime Ripard }
458619c15f7SMaxime Ripard 
sun4i_i2s_set_chan_cfg(const struct sun4i_i2s * i2s,unsigned int channels,unsigned int slots,unsigned int slot_width)459d70be625SMaxime Ripard static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
460c779e2deSClément Péron 				  unsigned int channels, unsigned int slots,
461c779e2deSClément Péron 				  unsigned int slot_width)
462fa7c0d13SMaxime Ripard {
463d70be625SMaxime Ripard 	/* Map the channels for playback and capture */
464d70be625SMaxime Ripard 	regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210);
465d70be625SMaxime Ripard 	regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210);
466d70be625SMaxime Ripard 
467d70be625SMaxime Ripard 	/* Configure the channels */
468d70be625SMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
469d70be625SMaxime Ripard 			   SUN4I_I2S_CHAN_SEL_MASK,
470d70be625SMaxime Ripard 			   SUN4I_I2S_CHAN_SEL(channels));
471d70be625SMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG,
472d70be625SMaxime Ripard 			   SUN4I_I2S_CHAN_SEL_MASK,
473d70be625SMaxime Ripard 			   SUN4I_I2S_CHAN_SEL(channels));
474d70be625SMaxime Ripard 
475d70be625SMaxime Ripard 	return 0;
4762ff739b9SChen-Yu Tsai }
477fa7c0d13SMaxime Ripard 
sun8i_i2s_set_chan_cfg(const struct sun4i_i2s * i2s,unsigned int channels,unsigned int slots,unsigned int slot_width)478d70be625SMaxime Ripard static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
479c779e2deSClément Péron 				  unsigned int channels, unsigned int slots,
480c779e2deSClément Péron 				  unsigned int slot_width)
481d70be625SMaxime Ripard {
4827ae7834eSMaxime Ripard 	unsigned int lrck_period;
483137befe1SMaxime Ripard 
484d70be625SMaxime Ripard 	/* Map the channels for playback and capture */
485d70be625SMaxime Ripard 	regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
486d70be625SMaxime Ripard 	regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210);
487d70be625SMaxime Ripard 
488d70be625SMaxime Ripard 	/* Configure the channels */
489d70be625SMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
490d70be625SMaxime Ripard 			   SUN4I_I2S_CHAN_SEL_MASK,
491d70be625SMaxime Ripard 			   SUN4I_I2S_CHAN_SEL(channels));
492d70be625SMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
493d70be625SMaxime Ripard 			   SUN4I_I2S_CHAN_SEL_MASK,
494d70be625SMaxime Ripard 			   SUN4I_I2S_CHAN_SEL(channels));
495d70be625SMaxime Ripard 
4967d299381SMarcus Cooper 	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
4977d299381SMarcus Cooper 			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
4987d299381SMarcus Cooper 			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
4997d299381SMarcus Cooper 	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
5007d299381SMarcus Cooper 			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
5017d299381SMarcus Cooper 			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
5027d299381SMarcus Cooper 
5037ae7834eSMaxime Ripard 	switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
5047ae7834eSMaxime Ripard 	case SND_SOC_DAIFMT_DSP_A:
5057ae7834eSMaxime Ripard 	case SND_SOC_DAIFMT_DSP_B:
506c779e2deSClément Péron 		lrck_period = slot_width * slots;
5077ae7834eSMaxime Ripard 		break;
5087ae7834eSMaxime Ripard 
50993c02106SClément Péron 	case SND_SOC_DAIFMT_LEFT_J:
51093c02106SClément Péron 	case SND_SOC_DAIFMT_RIGHT_J:
5117ae7834eSMaxime Ripard 	case SND_SOC_DAIFMT_I2S:
512c779e2deSClément Péron 		lrck_period = slot_width;
5137ae7834eSMaxime Ripard 		break;
5147ae7834eSMaxime Ripard 
5157ae7834eSMaxime Ripard 	default:
5167ae7834eSMaxime Ripard 		return -EINVAL;
5177ae7834eSMaxime Ripard 	}
5187ae7834eSMaxime Ripard 
5197ae7834eSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
5207ae7834eSMaxime Ripard 			   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
5217ae7834eSMaxime Ripard 			   SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
5227ae7834eSMaxime Ripard 
5237d299381SMarcus Cooper 	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
5247d299381SMarcus Cooper 			   SUN8I_I2S_TX_CHAN_EN_MASK,
5257d299381SMarcus Cooper 			   SUN8I_I2S_TX_CHAN_EN(channels));
5267d299381SMarcus Cooper 
527d70be625SMaxime Ripard 	return 0;
528d70be625SMaxime Ripard }
529d70be625SMaxime Ripard 
sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s * i2s,unsigned int channels,unsigned int slots,unsigned int slot_width)53073adf87bSJernej Skrabec static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s,
53173adf87bSJernej Skrabec 				      unsigned int channels, unsigned int slots,
53273adf87bSJernej Skrabec 				      unsigned int slot_width)
53373adf87bSJernej Skrabec {
53473adf87bSJernej Skrabec 	unsigned int lrck_period;
53573adf87bSJernej Skrabec 
53673adf87bSJernej Skrabec 	/* Map the channels for playback and capture */
537c8bbc1deSSamuel Holland 	regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0xFEDCBA98);
538c8bbc1deSSamuel Holland 	regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x76543210);
539e2ce580fSSamuel Holland 	if (i2s->variant->num_din_pins > 1) {
540e2ce580fSSamuel Holland 		regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP0_REG, 0x0F0E0D0C);
541e2ce580fSSamuel Holland 		regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP1_REG, 0x0B0A0908);
542e2ce580fSSamuel Holland 		regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP2_REG, 0x07060504);
543e2ce580fSSamuel Holland 		regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP3_REG, 0x03020100);
544e2ce580fSSamuel Holland 	} else {
54573adf87bSJernej Skrabec 		regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98);
54673adf87bSJernej Skrabec 		regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210);
547e2ce580fSSamuel Holland 	}
54873adf87bSJernej Skrabec 
54973adf87bSJernej Skrabec 	/* Configure the channels */
550c8bbc1deSSamuel Holland 	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0),
55173adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
55273adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_SEL(channels));
55373adf87bSJernej Skrabec 	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
55473adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_SEL_MASK,
55573adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_SEL(channels));
55673adf87bSJernej Skrabec 
55773adf87bSJernej Skrabec 	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
55873adf87bSJernej Skrabec 			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK,
55973adf87bSJernej Skrabec 			   SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels));
56073adf87bSJernej Skrabec 	regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG,
56173adf87bSJernej Skrabec 			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK,
56273adf87bSJernej Skrabec 			   SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels));
56373adf87bSJernej Skrabec 
56473adf87bSJernej Skrabec 	switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) {
56573adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_DSP_A:
56673adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_DSP_B:
56773adf87bSJernej Skrabec 		lrck_period = slot_width * slots;
56873adf87bSJernej Skrabec 		break;
56973adf87bSJernej Skrabec 
57073adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_LEFT_J:
57173adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_RIGHT_J:
57273adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_I2S:
57373adf87bSJernej Skrabec 		lrck_period = slot_width;
57473adf87bSJernej Skrabec 		break;
57573adf87bSJernej Skrabec 
57673adf87bSJernej Skrabec 	default:
57773adf87bSJernej Skrabec 		return -EINVAL;
57873adf87bSJernej Skrabec 	}
57973adf87bSJernej Skrabec 
58073adf87bSJernej Skrabec 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
58173adf87bSJernej Skrabec 			   SUN8I_I2S_FMT0_LRCK_PERIOD_MASK,
58273adf87bSJernej Skrabec 			   SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period));
58373adf87bSJernej Skrabec 
584c8bbc1deSSamuel Holland 	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0),
58573adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_EN_MASK,
58673adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_EN(channels));
58773adf87bSJernej Skrabec 
58873adf87bSJernej Skrabec 	return 0;
58973adf87bSJernej Skrabec }
59073adf87bSJernej Skrabec 
sun4i_i2s_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)591d70be625SMaxime Ripard static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
592d70be625SMaxime Ripard 			       struct snd_pcm_hw_params *params,
593d70be625SMaxime Ripard 			       struct snd_soc_dai *dai)
594d70be625SMaxime Ripard {
595d70be625SMaxime Ripard 	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
596137befe1SMaxime Ripard 	unsigned int word_size = params_width(params);
5975389f476SMaxime Ripard 	unsigned int slot_width = params_physical_width(params);
598bbf9a127SMaxime Ripard 	unsigned int channels = params_channels(params);
599c779e2deSClément Péron 
600137befe1SMaxime Ripard 	unsigned int slots = channels;
601c779e2deSClément Péron 
602d70be625SMaxime Ripard 	int ret, sr, wss;
603d70be625SMaxime Ripard 	u32 width;
604d70be625SMaxime Ripard 
605137befe1SMaxime Ripard 	if (i2s->slots)
606137befe1SMaxime Ripard 		slots = i2s->slots;
607137befe1SMaxime Ripard 
608137befe1SMaxime Ripard 	if (i2s->slot_width)
6095389f476SMaxime Ripard 		slot_width = i2s->slot_width;
610137befe1SMaxime Ripard 
611c779e2deSClément Péron 	ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width);
612d70be625SMaxime Ripard 	if (ret < 0) {
613d70be625SMaxime Ripard 		dev_err(dai->dev, "Invalid channel configuration\n");
614d70be625SMaxime Ripard 		return ret;
615d70be625SMaxime Ripard 	}
616d70be625SMaxime Ripard 
61738d7adc0SSamuel Holland 	/* Set significant bits in our FIFOs */
61838d7adc0SSamuel Holland 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
61938d7adc0SSamuel Holland 			   SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
62038d7adc0SSamuel Holland 			   SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
62138d7adc0SSamuel Holland 			   SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
62238d7adc0SSamuel Holland 			   SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
62338d7adc0SSamuel Holland 
624fa7c0d13SMaxime Ripard 	switch (params_physical_width(params)) {
625fa7c0d13SMaxime Ripard 	case 16:
626fa7c0d13SMaxime Ripard 		width = DMA_SLAVE_BUSWIDTH_2_BYTES;
627fa7c0d13SMaxime Ripard 		break;
6286ad7ca62SMarcus Cooper 	case 32:
6296ad7ca62SMarcus Cooper 		width = DMA_SLAVE_BUSWIDTH_4_BYTES;
6306ad7ca62SMarcus Cooper 		break;
631fa7c0d13SMaxime Ripard 	default:
6322ff739b9SChen-Yu Tsai 		dev_err(dai->dev, "Unsupported physical sample width: %d\n",
6332ff739b9SChen-Yu Tsai 			params_physical_width(params));
634fa7c0d13SMaxime Ripard 		return -EINVAL;
635fa7c0d13SMaxime Ripard 	}
636fa7c0d13SMaxime Ripard 	i2s->playback_dma_data.addr_width = width;
637fa7c0d13SMaxime Ripard 
6389c2d255fSClément Péron 	sr = i2s->variant->get_sr(word_size);
639619c15f7SMaxime Ripard 	if (sr < 0)
640fa7c0d13SMaxime Ripard 		return -EINVAL;
641fa7c0d13SMaxime Ripard 
6429c2d255fSClément Péron 	wss = i2s->variant->get_wss(slot_width);
643619c15f7SMaxime Ripard 	if (wss < 0)
644619c15f7SMaxime Ripard 		return -EINVAL;
645619c15f7SMaxime Ripard 
646619c15f7SMaxime Ripard 	regmap_field_write(i2s->field_fmt_wss, wss);
647619c15f7SMaxime Ripard 	regmap_field_write(i2s->field_fmt_sr, sr);
648fa7c0d13SMaxime Ripard 
6495389f476SMaxime Ripard 	return sun4i_i2s_set_clk_rate(dai, params_rate(params),
6505389f476SMaxime Ripard 				      slots, slot_width);
651fa7c0d13SMaxime Ripard }
652fa7c0d13SMaxime Ripard 
sun4i_i2s_set_soc_fmt(const struct sun4i_i2s * i2s,unsigned int fmt)65371137bcdSMaxime Ripard static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
65471137bcdSMaxime Ripard 				 unsigned int fmt)
655fa7c0d13SMaxime Ripard {
656fa7c0d13SMaxime Ripard 	u32 val;
657fa7c0d13SMaxime Ripard 
658515fcfbcSMaxime Ripard 	/* DAI clock polarity */
659515fcfbcSMaxime Ripard 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
660515fcfbcSMaxime Ripard 	case SND_SOC_DAIFMT_IB_IF:
661515fcfbcSMaxime Ripard 		/* Invert both clocks */
662515fcfbcSMaxime Ripard 		val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
663515fcfbcSMaxime Ripard 		      SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
664515fcfbcSMaxime Ripard 		break;
665515fcfbcSMaxime Ripard 	case SND_SOC_DAIFMT_IB_NF:
666515fcfbcSMaxime Ripard 		/* Invert bit clock */
667515fcfbcSMaxime Ripard 		val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED;
668515fcfbcSMaxime Ripard 		break;
669515fcfbcSMaxime Ripard 	case SND_SOC_DAIFMT_NB_IF:
670515fcfbcSMaxime Ripard 		/* Invert frame clock */
671515fcfbcSMaxime Ripard 		val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
672515fcfbcSMaxime Ripard 		break;
673515fcfbcSMaxime Ripard 	case SND_SOC_DAIFMT_NB_NF:
674515fcfbcSMaxime Ripard 		val = 0;
675515fcfbcSMaxime Ripard 		break;
676515fcfbcSMaxime Ripard 	default:
677515fcfbcSMaxime Ripard 		return -EINVAL;
678515fcfbcSMaxime Ripard 	}
679515fcfbcSMaxime Ripard 
680515fcfbcSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
681515fcfbcSMaxime Ripard 			   SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK |
682515fcfbcSMaxime Ripard 			   SUN4I_I2S_FMT0_BCLK_POLARITY_MASK,
683515fcfbcSMaxime Ripard 			   val);
684515fcfbcSMaxime Ripard 
685fa7c0d13SMaxime Ripard 	/* DAI Mode */
686fa7c0d13SMaxime Ripard 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
687fa7c0d13SMaxime Ripard 	case SND_SOC_DAIFMT_I2S:
688fa7c0d13SMaxime Ripard 		val = SUN4I_I2S_FMT0_FMT_I2S;
689fa7c0d13SMaxime Ripard 		break;
69071137bcdSMaxime Ripard 
691fa7c0d13SMaxime Ripard 	case SND_SOC_DAIFMT_LEFT_J:
692fa7c0d13SMaxime Ripard 		val = SUN4I_I2S_FMT0_FMT_LEFT_J;
693fa7c0d13SMaxime Ripard 		break;
69471137bcdSMaxime Ripard 
695fa7c0d13SMaxime Ripard 	case SND_SOC_DAIFMT_RIGHT_J:
696fa7c0d13SMaxime Ripard 		val = SUN4I_I2S_FMT0_FMT_RIGHT_J;
697fa7c0d13SMaxime Ripard 		break;
69871137bcdSMaxime Ripard 
699fa7c0d13SMaxime Ripard 	default:
700fa7c0d13SMaxime Ripard 		return -EINVAL;
701fa7c0d13SMaxime Ripard 	}
702fa7c0d13SMaxime Ripard 
70371137bcdSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
70471137bcdSMaxime Ripard 			   SUN4I_I2S_FMT0_FMT_MASK, val);
70571137bcdSMaxime Ripard 
70671137bcdSMaxime Ripard 	/* DAI clock master masks */
7077cc3965fSCharles Keepax 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
7087cc3965fSCharles Keepax 	case SND_SOC_DAIFMT_BP_FP:
70971137bcdSMaxime Ripard 		/* BCLK and LRCLK master */
71071137bcdSMaxime Ripard 		val = SUN4I_I2S_CTRL_MODE_MASTER;
71171137bcdSMaxime Ripard 		break;
71271137bcdSMaxime Ripard 
7137cc3965fSCharles Keepax 	case SND_SOC_DAIFMT_BC_FC:
71471137bcdSMaxime Ripard 		/* BCLK and LRCLK slave */
71571137bcdSMaxime Ripard 		val = SUN4I_I2S_CTRL_MODE_SLAVE;
71671137bcdSMaxime Ripard 		break;
71771137bcdSMaxime Ripard 
71871137bcdSMaxime Ripard 	default:
71971137bcdSMaxime Ripard 		return -EINVAL;
72071137bcdSMaxime Ripard 	}
72171137bcdSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
72271137bcdSMaxime Ripard 			   SUN4I_I2S_CTRL_MODE_MASK, val);
723d8659dd9SMarcus Cooper 
72471137bcdSMaxime Ripard 	return 0;
72571137bcdSMaxime Ripard }
72671137bcdSMaxime Ripard 
sun8i_i2s_set_soc_fmt(const struct sun4i_i2s * i2s,unsigned int fmt)72771137bcdSMaxime Ripard static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
72871137bcdSMaxime Ripard 				 unsigned int fmt)
72971137bcdSMaxime Ripard {
730*b9bb9634SMatteo Martelli 	u32 mode, lrclk_pol, bclk_pol, val;
73171137bcdSMaxime Ripard 	u8 offset;
73271137bcdSMaxime Ripard 
73371137bcdSMaxime Ripard 	/* DAI Mode */
73471137bcdSMaxime Ripard 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
7357ae7834eSMaxime Ripard 	case SND_SOC_DAIFMT_DSP_A:
736*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
7377ae7834eSMaxime Ripard 		mode = SUN8I_I2S_CTRL_MODE_PCM;
7387ae7834eSMaxime Ripard 		offset = 1;
7397ae7834eSMaxime Ripard 		break;
7407ae7834eSMaxime Ripard 
7417ae7834eSMaxime Ripard 	case SND_SOC_DAIFMT_DSP_B:
742*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
7437ae7834eSMaxime Ripard 		mode = SUN8I_I2S_CTRL_MODE_PCM;
7447ae7834eSMaxime Ripard 		offset = 0;
7457ae7834eSMaxime Ripard 		break;
7467ae7834eSMaxime Ripard 
74771137bcdSMaxime Ripard 	case SND_SOC_DAIFMT_I2S:
748*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_LOW;
74971137bcdSMaxime Ripard 		mode = SUN8I_I2S_CTRL_MODE_LEFT;
75071137bcdSMaxime Ripard 		offset = 1;
75171137bcdSMaxime Ripard 		break;
75271137bcdSMaxime Ripard 
75371137bcdSMaxime Ripard 	case SND_SOC_DAIFMT_LEFT_J:
754*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
75571137bcdSMaxime Ripard 		mode = SUN8I_I2S_CTRL_MODE_LEFT;
75671137bcdSMaxime Ripard 		offset = 0;
75771137bcdSMaxime Ripard 		break;
75871137bcdSMaxime Ripard 
75971137bcdSMaxime Ripard 	case SND_SOC_DAIFMT_RIGHT_J:
760*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
76171137bcdSMaxime Ripard 		mode = SUN8I_I2S_CTRL_MODE_RIGHT;
76271137bcdSMaxime Ripard 		offset = 0;
76371137bcdSMaxime Ripard 		break;
76471137bcdSMaxime Ripard 
76571137bcdSMaxime Ripard 	default:
76671137bcdSMaxime Ripard 		return -EINVAL;
76771137bcdSMaxime Ripard 	}
76871137bcdSMaxime Ripard 
76971137bcdSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
77071137bcdSMaxime Ripard 			   SUN8I_I2S_CTRL_MODE_MASK, mode);
7717d299381SMarcus Cooper 	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
7727d299381SMarcus Cooper 			   SUN8I_I2S_TX_CHAN_OFFSET_MASK,
7737d299381SMarcus Cooper 			   SUN8I_I2S_TX_CHAN_OFFSET(offset));
774f9927000SMarcus Cooper 	regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
775f9927000SMarcus Cooper 			   SUN8I_I2S_TX_CHAN_OFFSET_MASK,
776f9927000SMarcus Cooper 			   SUN8I_I2S_TX_CHAN_OFFSET(offset));
77771137bcdSMaxime Ripard 
778*b9bb9634SMatteo Martelli 	/* DAI clock polarity */
779*b9bb9634SMatteo Martelli 	bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL;
780*b9bb9634SMatteo Martelli 
781*b9bb9634SMatteo Martelli 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
782*b9bb9634SMatteo Martelli 	case SND_SOC_DAIFMT_IB_IF:
783*b9bb9634SMatteo Martelli 		/* Invert both clocks */
784*b9bb9634SMatteo Martelli 		lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;
785*b9bb9634SMatteo Martelli 		bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
786*b9bb9634SMatteo Martelli 		break;
787*b9bb9634SMatteo Martelli 	case SND_SOC_DAIFMT_IB_NF:
788*b9bb9634SMatteo Martelli 		/* Invert bit clock */
789*b9bb9634SMatteo Martelli 		bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
790*b9bb9634SMatteo Martelli 		break;
791*b9bb9634SMatteo Martelli 	case SND_SOC_DAIFMT_NB_IF:
792*b9bb9634SMatteo Martelli 		/* Invert frame clock */
793*b9bb9634SMatteo Martelli 		lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;
794*b9bb9634SMatteo Martelli 		break;
795*b9bb9634SMatteo Martelli 	case SND_SOC_DAIFMT_NB_NF:
796*b9bb9634SMatteo Martelli 		/* No inversion */
797*b9bb9634SMatteo Martelli 		break;
798*b9bb9634SMatteo Martelli 	default:
799*b9bb9634SMatteo Martelli 		return -EINVAL;
800*b9bb9634SMatteo Martelli 	}
801*b9bb9634SMatteo Martelli 
802*b9bb9634SMatteo Martelli 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
803*b9bb9634SMatteo Martelli 			   SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
804*b9bb9634SMatteo Martelli 			   SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
805*b9bb9634SMatteo Martelli 			   lrclk_pol | bclk_pol);
806*b9bb9634SMatteo Martelli 
80771137bcdSMaxime Ripard 	/* DAI clock master masks */
8087cc3965fSCharles Keepax 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
8097cc3965fSCharles Keepax 	case SND_SOC_DAIFMT_BP_FP:
81071137bcdSMaxime Ripard 		/* BCLK and LRCLK master */
81171137bcdSMaxime Ripard 		val = SUN8I_I2S_CTRL_BCLK_OUT |	SUN8I_I2S_CTRL_LRCK_OUT;
81271137bcdSMaxime Ripard 		break;
81371137bcdSMaxime Ripard 
8147cc3965fSCharles Keepax 	case SND_SOC_DAIFMT_BC_FC:
81571137bcdSMaxime Ripard 		/* BCLK and LRCLK slave */
81671137bcdSMaxime Ripard 		val = 0;
81771137bcdSMaxime Ripard 		break;
81871137bcdSMaxime Ripard 
81971137bcdSMaxime Ripard 	default:
82071137bcdSMaxime Ripard 		return -EINVAL;
8217d299381SMarcus Cooper 	}
8227d299381SMarcus Cooper 
82371137bcdSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
82471137bcdSMaxime Ripard 			   SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
82571137bcdSMaxime Ripard 			   val);
82671137bcdSMaxime Ripard 
827d8659dd9SMarcus Cooper 	/* Set sign extension to pad out LSB with 0 */
828d8659dd9SMarcus Cooper 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
829d8659dd9SMarcus Cooper 			   SUN8I_I2S_FMT1_REG_SEXT_MASK,
830d8659dd9SMarcus Cooper 			   SUN8I_I2S_FMT1_REG_SEXT(0));
831d8659dd9SMarcus Cooper 
83271137bcdSMaxime Ripard 	return 0;
83371137bcdSMaxime Ripard }
83471137bcdSMaxime Ripard 
sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s * i2s,unsigned int fmt)83573adf87bSJernej Skrabec static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
83673adf87bSJernej Skrabec 				     unsigned int fmt)
83773adf87bSJernej Skrabec {
838*b9bb9634SMatteo Martelli 	u32 mode, lrclk_pol, bclk_pol, val;
83973adf87bSJernej Skrabec 	u8 offset;
84073adf87bSJernej Skrabec 
84173adf87bSJernej Skrabec 	/* DAI Mode */
84273adf87bSJernej Skrabec 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
84373adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_DSP_A:
844*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
84573adf87bSJernej Skrabec 		mode = SUN8I_I2S_CTRL_MODE_PCM;
84673adf87bSJernej Skrabec 		offset = 1;
84773adf87bSJernej Skrabec 		break;
84873adf87bSJernej Skrabec 
84973adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_DSP_B:
850*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
85173adf87bSJernej Skrabec 		mode = SUN8I_I2S_CTRL_MODE_PCM;
85273adf87bSJernej Skrabec 		offset = 0;
85373adf87bSJernej Skrabec 		break;
85473adf87bSJernej Skrabec 
85573adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_I2S:
856*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_LOW;
85773adf87bSJernej Skrabec 		mode = SUN8I_I2S_CTRL_MODE_LEFT;
85873adf87bSJernej Skrabec 		offset = 1;
85973adf87bSJernej Skrabec 		break;
86073adf87bSJernej Skrabec 
86173adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_LEFT_J:
862*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
86373adf87bSJernej Skrabec 		mode = SUN8I_I2S_CTRL_MODE_LEFT;
86473adf87bSJernej Skrabec 		offset = 0;
86573adf87bSJernej Skrabec 		break;
86673adf87bSJernej Skrabec 
86773adf87bSJernej Skrabec 	case SND_SOC_DAIFMT_RIGHT_J:
868*b9bb9634SMatteo Martelli 		lrclk_pol = SUN8I_I2S_FMT0_LRCLK_POLARITY_START_HIGH;
86973adf87bSJernej Skrabec 		mode = SUN8I_I2S_CTRL_MODE_RIGHT;
87073adf87bSJernej Skrabec 		offset = 0;
87173adf87bSJernej Skrabec 		break;
87273adf87bSJernej Skrabec 
87373adf87bSJernej Skrabec 	default:
87473adf87bSJernej Skrabec 		return -EINVAL;
87573adf87bSJernej Skrabec 	}
87673adf87bSJernej Skrabec 
87773adf87bSJernej Skrabec 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
87873adf87bSJernej Skrabec 			   SUN8I_I2S_CTRL_MODE_MASK, mode);
87973adf87bSJernej Skrabec 	regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
88073adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
88173adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
88273adf87bSJernej Skrabec 	regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG,
88373adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK,
88473adf87bSJernej Skrabec 			   SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset));
88573adf87bSJernej Skrabec 
886*b9bb9634SMatteo Martelli 	/* DAI clock polarity */
887*b9bb9634SMatteo Martelli 	bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL;
888*b9bb9634SMatteo Martelli 
889*b9bb9634SMatteo Martelli 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
890*b9bb9634SMatteo Martelli 	case SND_SOC_DAIFMT_IB_IF:
891*b9bb9634SMatteo Martelli 		/* Invert both clocks */
892*b9bb9634SMatteo Martelli 		lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;
893*b9bb9634SMatteo Martelli 		bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
894*b9bb9634SMatteo Martelli 		break;
895*b9bb9634SMatteo Martelli 	case SND_SOC_DAIFMT_IB_NF:
896*b9bb9634SMatteo Martelli 		/* Invert bit clock */
897*b9bb9634SMatteo Martelli 		bclk_pol = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED;
898*b9bb9634SMatteo Martelli 		break;
899*b9bb9634SMatteo Martelli 	case SND_SOC_DAIFMT_NB_IF:
900*b9bb9634SMatteo Martelli 		/* Invert frame clock */
901*b9bb9634SMatteo Martelli 		lrclk_pol ^= SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK;
902*b9bb9634SMatteo Martelli 		break;
903*b9bb9634SMatteo Martelli 	case SND_SOC_DAIFMT_NB_NF:
904*b9bb9634SMatteo Martelli 		/* No inversion */
905*b9bb9634SMatteo Martelli 		break;
906*b9bb9634SMatteo Martelli 	default:
907*b9bb9634SMatteo Martelli 		return -EINVAL;
908*b9bb9634SMatteo Martelli 	}
909*b9bb9634SMatteo Martelli 
910*b9bb9634SMatteo Martelli 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
911*b9bb9634SMatteo Martelli 			   SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK |
912*b9bb9634SMatteo Martelli 			   SUN8I_I2S_FMT0_BCLK_POLARITY_MASK,
913*b9bb9634SMatteo Martelli 			   lrclk_pol | bclk_pol);
914*b9bb9634SMatteo Martelli 
915*b9bb9634SMatteo Martelli 
91673adf87bSJernej Skrabec 	/* DAI clock master masks */
9177cc3965fSCharles Keepax 	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
9187cc3965fSCharles Keepax 	case SND_SOC_DAIFMT_BP_FP:
91973adf87bSJernej Skrabec 		/* BCLK and LRCLK master */
92073adf87bSJernej Skrabec 		val = SUN8I_I2S_CTRL_BCLK_OUT |	SUN8I_I2S_CTRL_LRCK_OUT;
92173adf87bSJernej Skrabec 		break;
92273adf87bSJernej Skrabec 
9237cc3965fSCharles Keepax 	case SND_SOC_DAIFMT_BC_FC:
92473adf87bSJernej Skrabec 		/* BCLK and LRCLK slave */
92573adf87bSJernej Skrabec 		val = 0;
92673adf87bSJernej Skrabec 		break;
92773adf87bSJernej Skrabec 
92873adf87bSJernej Skrabec 	default:
92973adf87bSJernej Skrabec 		return -EINVAL;
93073adf87bSJernej Skrabec 	}
93173adf87bSJernej Skrabec 
93273adf87bSJernej Skrabec 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
93373adf87bSJernej Skrabec 			   SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT,
93473adf87bSJernej Skrabec 			   val);
93573adf87bSJernej Skrabec 
936d8659dd9SMarcus Cooper 	/* Set sign extension to pad out LSB with 0 */
937d8659dd9SMarcus Cooper 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG,
938d8659dd9SMarcus Cooper 			   SUN8I_I2S_FMT1_REG_SEXT_MASK,
939d8659dd9SMarcus Cooper 			   SUN8I_I2S_FMT1_REG_SEXT(0));
940d8659dd9SMarcus Cooper 
94173adf87bSJernej Skrabec 	return 0;
94273adf87bSJernej Skrabec }
94373adf87bSJernej Skrabec 
sun4i_i2s_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)94471137bcdSMaxime Ripard static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
94571137bcdSMaxime Ripard {
94671137bcdSMaxime Ripard 	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
94771137bcdSMaxime Ripard 	int ret;
948fa7c0d13SMaxime Ripard 
94971137bcdSMaxime Ripard 	ret = i2s->variant->set_fmt(i2s, fmt);
95071137bcdSMaxime Ripard 	if (ret) {
95171137bcdSMaxime Ripard 		dev_err(dai->dev, "Unsupported format configuration\n");
95271137bcdSMaxime Ripard 		return ret;
953d03d2737SMarcus Cooper 	}
954fa7c0d13SMaxime Ripard 
9557ae7834eSMaxime Ripard 	i2s->format = fmt;
9567ae7834eSMaxime Ripard 
957fa7c0d13SMaxime Ripard 	return 0;
958fa7c0d13SMaxime Ripard }
959fa7c0d13SMaxime Ripard 
sun4i_i2s_start_capture(struct sun4i_i2s * i2s)960ae73b34fSMaxime Ripard static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
961ae73b34fSMaxime Ripard {
962ae73b34fSMaxime Ripard 	/* Flush RX FIFO */
963ae73b34fSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
964ae73b34fSMaxime Ripard 			   SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
965ae73b34fSMaxime Ripard 			   SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
966ae73b34fSMaxime Ripard 
967ae73b34fSMaxime Ripard 	/* Clear RX counter */
968ae73b34fSMaxime Ripard 	regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0);
969ae73b34fSMaxime Ripard 
970ae73b34fSMaxime Ripard 	/* Enable RX Block */
971ae73b34fSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
972ae73b34fSMaxime Ripard 			   SUN4I_I2S_CTRL_RX_EN,
973ae73b34fSMaxime Ripard 			   SUN4I_I2S_CTRL_RX_EN);
974ae73b34fSMaxime Ripard 
975ae73b34fSMaxime Ripard 	/* Enable RX DRQ */
976ae73b34fSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
977ae73b34fSMaxime Ripard 			   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
978ae73b34fSMaxime Ripard 			   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN);
979ae73b34fSMaxime Ripard }
980ae73b34fSMaxime Ripard 
sun4i_i2s_start_playback(struct sun4i_i2s * i2s)981fa7c0d13SMaxime Ripard static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
982fa7c0d13SMaxime Ripard {
983fa7c0d13SMaxime Ripard 	/* Flush TX FIFO */
984fa7c0d13SMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
985fa7c0d13SMaxime Ripard 			   SUN4I_I2S_FIFO_CTRL_FLUSH_TX,
986fa7c0d13SMaxime Ripard 			   SUN4I_I2S_FIFO_CTRL_FLUSH_TX);
987fa7c0d13SMaxime Ripard 
988fa7c0d13SMaxime Ripard 	/* Clear TX counter */
989fa7c0d13SMaxime Ripard 	regmap_write(i2s->regmap, SUN4I_I2S_TX_CNT_REG, 0);
990fa7c0d13SMaxime Ripard 
991fa7c0d13SMaxime Ripard 	/* Enable TX Block */
992fa7c0d13SMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
993fa7c0d13SMaxime Ripard 			   SUN4I_I2S_CTRL_TX_EN,
994fa7c0d13SMaxime Ripard 			   SUN4I_I2S_CTRL_TX_EN);
995fa7c0d13SMaxime Ripard 
996fa7c0d13SMaxime Ripard 	/* Enable TX DRQ */
997fa7c0d13SMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
998fa7c0d13SMaxime Ripard 			   SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN,
999fa7c0d13SMaxime Ripard 			   SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN);
1000fa7c0d13SMaxime Ripard }
1001fa7c0d13SMaxime Ripard 
sun4i_i2s_stop_capture(struct sun4i_i2s * i2s)1002ae73b34fSMaxime Ripard static void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s)
1003ae73b34fSMaxime Ripard {
1004ae73b34fSMaxime Ripard 	/* Disable RX Block */
1005ae73b34fSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
1006ae73b34fSMaxime Ripard 			   SUN4I_I2S_CTRL_RX_EN,
1007ae73b34fSMaxime Ripard 			   0);
1008ae73b34fSMaxime Ripard 
1009ae73b34fSMaxime Ripard 	/* Disable RX DRQ */
1010ae73b34fSMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
1011ae73b34fSMaxime Ripard 			   SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
1012ae73b34fSMaxime Ripard 			   0);
1013ae73b34fSMaxime Ripard }
1014fa7c0d13SMaxime Ripard 
sun4i_i2s_stop_playback(struct sun4i_i2s * i2s)1015fa7c0d13SMaxime Ripard static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s)
1016fa7c0d13SMaxime Ripard {
1017fa7c0d13SMaxime Ripard 	/* Disable TX Block */
1018fa7c0d13SMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
1019fa7c0d13SMaxime Ripard 			   SUN4I_I2S_CTRL_TX_EN,
1020fa7c0d13SMaxime Ripard 			   0);
1021fa7c0d13SMaxime Ripard 
1022fa7c0d13SMaxime Ripard 	/* Disable TX DRQ */
1023fa7c0d13SMaxime Ripard 	regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
1024fa7c0d13SMaxime Ripard 			   SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN,
1025fa7c0d13SMaxime Ripard 			   0);
1026fa7c0d13SMaxime Ripard }
1027fa7c0d13SMaxime Ripard 
sun4i_i2s_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)1028fa7c0d13SMaxime Ripard static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
1029fa7c0d13SMaxime Ripard 			     struct snd_soc_dai *dai)
1030fa7c0d13SMaxime Ripard {
1031fa7c0d13SMaxime Ripard 	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
1032fa7c0d13SMaxime Ripard 
1033fa7c0d13SMaxime Ripard 	switch (cmd) {
1034fa7c0d13SMaxime Ripard 	case SNDRV_PCM_TRIGGER_START:
1035fa7c0d13SMaxime Ripard 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1036fa7c0d13SMaxime Ripard 	case SNDRV_PCM_TRIGGER_RESUME:
1037fa7c0d13SMaxime Ripard 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1038fa7c0d13SMaxime Ripard 			sun4i_i2s_start_playback(i2s);
1039fa7c0d13SMaxime Ripard 		else
1040ae73b34fSMaxime Ripard 			sun4i_i2s_start_capture(i2s);
1041fa7c0d13SMaxime Ripard 		break;
1042fa7c0d13SMaxime Ripard 
1043fa7c0d13SMaxime Ripard 	case SNDRV_PCM_TRIGGER_STOP:
1044fa7c0d13SMaxime Ripard 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1045fa7c0d13SMaxime Ripard 	case SNDRV_PCM_TRIGGER_SUSPEND:
1046fa7c0d13SMaxime Ripard 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1047fa7c0d13SMaxime Ripard 			sun4i_i2s_stop_playback(i2s);
1048fa7c0d13SMaxime Ripard 		else
1049ae73b34fSMaxime Ripard 			sun4i_i2s_stop_capture(i2s);
1050fa7c0d13SMaxime Ripard 		break;
1051fa7c0d13SMaxime Ripard 
1052fa7c0d13SMaxime Ripard 	default:
1053fa7c0d13SMaxime Ripard 		return -EINVAL;
1054fa7c0d13SMaxime Ripard 	}
1055fa7c0d13SMaxime Ripard 
1056fa7c0d13SMaxime Ripard 	return 0;
1057fa7c0d13SMaxime Ripard }
1058fa7c0d13SMaxime Ripard 
sun4i_i2s_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)1059b2b7b56fSMaxime Ripard static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
1060b2b7b56fSMaxime Ripard 				unsigned int freq, int dir)
1061b2b7b56fSMaxime Ripard {
1062b2b7b56fSMaxime Ripard 	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
1063b2b7b56fSMaxime Ripard 
1064b2b7b56fSMaxime Ripard 	if (clk_id != 0)
1065b2b7b56fSMaxime Ripard 		return -EINVAL;
1066b2b7b56fSMaxime Ripard 
1067b2b7b56fSMaxime Ripard 	i2s->mclk_freq = freq;
1068b2b7b56fSMaxime Ripard 
1069b2b7b56fSMaxime Ripard 	return 0;
1070b2b7b56fSMaxime Ripard }
1071b2b7b56fSMaxime Ripard 
sun4i_i2s_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)1072137befe1SMaxime Ripard static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,
1073137befe1SMaxime Ripard 				  unsigned int tx_mask, unsigned int rx_mask,
1074137befe1SMaxime Ripard 				  int slots, int slot_width)
1075137befe1SMaxime Ripard {
1076137befe1SMaxime Ripard 	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
1077137befe1SMaxime Ripard 
1078137befe1SMaxime Ripard 	if (slots > 8)
1079137befe1SMaxime Ripard 		return -EINVAL;
1080137befe1SMaxime Ripard 
1081137befe1SMaxime Ripard 	i2s->slots = slots;
1082137befe1SMaxime Ripard 	i2s->slot_width = slot_width;
1083137befe1SMaxime Ripard 
1084137befe1SMaxime Ripard 	return 0;
1085137befe1SMaxime Ripard }
1086137befe1SMaxime Ripard 
sun4i_i2s_dai_probe(struct snd_soc_dai * dai)1087fa7c0d13SMaxime Ripard static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
1088fa7c0d13SMaxime Ripard {
1089fa7c0d13SMaxime Ripard 	struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
1090fa7c0d13SMaxime Ripard 
1091ae73b34fSMaxime Ripard 	snd_soc_dai_init_dma_data(dai,
1092ae73b34fSMaxime Ripard 				  &i2s->playback_dma_data,
1093ae73b34fSMaxime Ripard 				  &i2s->capture_dma_data);
1094fa7c0d13SMaxime Ripard 
1095fa7c0d13SMaxime Ripard 	return 0;
1096fa7c0d13SMaxime Ripard }
1097fa7c0d13SMaxime Ripard 
1098fc95a8a3SKuninori Morimoto static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
1099fc95a8a3SKuninori Morimoto 	.probe		= sun4i_i2s_dai_probe,
1100fc95a8a3SKuninori Morimoto 	.hw_params	= sun4i_i2s_hw_params,
1101fc95a8a3SKuninori Morimoto 	.set_fmt	= sun4i_i2s_set_fmt,
1102fc95a8a3SKuninori Morimoto 	.set_sysclk	= sun4i_i2s_set_sysclk,
1103fc95a8a3SKuninori Morimoto 	.set_tdm_slot	= sun4i_i2s_set_tdm_slot,
1104fc95a8a3SKuninori Morimoto 	.trigger	= sun4i_i2s_trigger,
1105fc95a8a3SKuninori Morimoto };
1106fc95a8a3SKuninori Morimoto 
11076ad7ca62SMarcus Cooper #define SUN4I_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | \
11086ad7ca62SMarcus Cooper 			 SNDRV_PCM_FMTBIT_S20_LE | \
11096ad7ca62SMarcus Cooper 			 SNDRV_PCM_FMTBIT_S24_LE)
11106ad7ca62SMarcus Cooper 
1111fa7c0d13SMaxime Ripard static struct snd_soc_dai_driver sun4i_i2s_dai = {
1112ae73b34fSMaxime Ripard 	.capture = {
1113ae73b34fSMaxime Ripard 		.stream_name = "Capture",
1114bbf9a127SMaxime Ripard 		.channels_min = 1,
1115bbf9a127SMaxime Ripard 		.channels_max = 8,
1116ae73b34fSMaxime Ripard 		.rates = SNDRV_PCM_RATE_8000_192000,
11176ad7ca62SMarcus Cooper 		.formats = SUN4I_FORMATS,
1118ae73b34fSMaxime Ripard 	},
1119fa7c0d13SMaxime Ripard 	.playback = {
1120fa7c0d13SMaxime Ripard 		.stream_name = "Playback",
1121bbf9a127SMaxime Ripard 		.channels_min = 1,
1122bbf9a127SMaxime Ripard 		.channels_max = 8,
1123fa7c0d13SMaxime Ripard 		.rates = SNDRV_PCM_RATE_8000_192000,
11246ad7ca62SMarcus Cooper 		.formats = SUN4I_FORMATS,
1125fa7c0d13SMaxime Ripard 	},
1126fa7c0d13SMaxime Ripard 	.ops = &sun4i_i2s_dai_ops,
112781385708SKuninori Morimoto 	.symmetric_rate = 1,
1128fa7c0d13SMaxime Ripard };
1129fa7c0d13SMaxime Ripard 
1130fa7c0d13SMaxime Ripard static const struct snd_soc_component_driver sun4i_i2s_component = {
1131fa7c0d13SMaxime Ripard 	.name			= "sun4i-dai",
1132f450b5dbSCharles Keepax 	.legacy_dai_naming	= 1,
1133fa7c0d13SMaxime Ripard };
1134fa7c0d13SMaxime Ripard 
sun4i_i2s_rd_reg(struct device * dev,unsigned int reg)1135fa7c0d13SMaxime Ripard static bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg)
1136fa7c0d13SMaxime Ripard {
1137fa7c0d13SMaxime Ripard 	switch (reg) {
1138fa7c0d13SMaxime Ripard 	case SUN4I_I2S_FIFO_TX_REG:
1139fa7c0d13SMaxime Ripard 		return false;
1140fa7c0d13SMaxime Ripard 
1141fa7c0d13SMaxime Ripard 	default:
1142fa7c0d13SMaxime Ripard 		return true;
1143fa7c0d13SMaxime Ripard 	}
1144fa7c0d13SMaxime Ripard }
1145fa7c0d13SMaxime Ripard 
sun4i_i2s_wr_reg(struct device * dev,unsigned int reg)1146fa7c0d13SMaxime Ripard static bool sun4i_i2s_wr_reg(struct device *dev, unsigned int reg)
1147fa7c0d13SMaxime Ripard {
1148fa7c0d13SMaxime Ripard 	switch (reg) {
1149fa7c0d13SMaxime Ripard 	case SUN4I_I2S_FIFO_RX_REG:
1150fa7c0d13SMaxime Ripard 	case SUN4I_I2S_FIFO_STA_REG:
1151fa7c0d13SMaxime Ripard 		return false;
1152fa7c0d13SMaxime Ripard 
1153fa7c0d13SMaxime Ripard 	default:
1154fa7c0d13SMaxime Ripard 		return true;
1155fa7c0d13SMaxime Ripard 	}
1156fa7c0d13SMaxime Ripard }
1157fa7c0d13SMaxime Ripard 
sun4i_i2s_volatile_reg(struct device * dev,unsigned int reg)1158fa7c0d13SMaxime Ripard static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg)
1159fa7c0d13SMaxime Ripard {
1160fa7c0d13SMaxime Ripard 	switch (reg) {
1161fa7c0d13SMaxime Ripard 	case SUN4I_I2S_FIFO_RX_REG:
1162fa7c0d13SMaxime Ripard 	case SUN4I_I2S_INT_STA_REG:
1163fa7c0d13SMaxime Ripard 	case SUN4I_I2S_RX_CNT_REG:
1164fa7c0d13SMaxime Ripard 	case SUN4I_I2S_TX_CNT_REG:
1165fa7c0d13SMaxime Ripard 		return true;
1166fa7c0d13SMaxime Ripard 
1167fa7c0d13SMaxime Ripard 	default:
1168fa7c0d13SMaxime Ripard 		return false;
1169fa7c0d13SMaxime Ripard 	}
1170fa7c0d13SMaxime Ripard }
1171fa7c0d13SMaxime Ripard 
sun8i_i2s_rd_reg(struct device * dev,unsigned int reg)11727d299381SMarcus Cooper static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg)
11737d299381SMarcus Cooper {
11747d299381SMarcus Cooper 	switch (reg) {
11757d299381SMarcus Cooper 	case SUN8I_I2S_FIFO_TX_REG:
11767d299381SMarcus Cooper 		return false;
11777d299381SMarcus Cooper 
11787d299381SMarcus Cooper 	default:
11797d299381SMarcus Cooper 		return true;
11807d299381SMarcus Cooper 	}
11817d299381SMarcus Cooper }
11827d299381SMarcus Cooper 
sun8i_i2s_volatile_reg(struct device * dev,unsigned int reg)11837d299381SMarcus Cooper static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg)
11847d299381SMarcus Cooper {
118564359246SClément Péron 	switch (reg) {
118664359246SClément Péron 	case SUN4I_I2S_FIFO_CTRL_REG:
118764359246SClément Péron 	case SUN4I_I2S_FIFO_RX_REG:
118864359246SClément Péron 	case SUN4I_I2S_FIFO_STA_REG:
118964359246SClément Péron 	case SUN4I_I2S_RX_CNT_REG:
119064359246SClément Péron 	case SUN4I_I2S_TX_CNT_REG:
119164359246SClément Péron 	case SUN8I_I2S_FIFO_TX_REG:
119264359246SClément Péron 	case SUN8I_I2S_INT_STA_REG:
11937d299381SMarcus Cooper 		return true;
11947d299381SMarcus Cooper 
119564359246SClément Péron 	default:
119664359246SClément Péron 		return false;
119764359246SClément Péron 	}
11987d299381SMarcus Cooper }
11997d299381SMarcus Cooper 
1200fa7c0d13SMaxime Ripard static const struct reg_default sun4i_i2s_reg_defaults[] = {
1201fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_CTRL_REG, 0x00000000 },
1202fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_FMT0_REG, 0x0000000c },
1203fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_FMT1_REG, 0x00004020 },
1204fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
1205fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
1206fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
1207fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_TX_CHAN_SEL_REG, 0x00000001 },
1208fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210 },
1209fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_RX_CHAN_SEL_REG, 0x00000001 },
1210fa7c0d13SMaxime Ripard 	{ SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 },
1211fa7c0d13SMaxime Ripard };
1212fa7c0d13SMaxime Ripard 
12137d299381SMarcus Cooper static const struct reg_default sun8i_i2s_reg_defaults[] = {
12147d299381SMarcus Cooper 	{ SUN4I_I2S_CTRL_REG, 0x00060000 },
12157d299381SMarcus Cooper 	{ SUN4I_I2S_FMT0_REG, 0x00000033 },
12167d299381SMarcus Cooper 	{ SUN4I_I2S_FMT1_REG, 0x00000030 },
12177d299381SMarcus Cooper 	{ SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
12187d299381SMarcus Cooper 	{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
12197d299381SMarcus Cooper 	{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
12207d299381SMarcus Cooper 	{ SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
12217d299381SMarcus Cooper 	{ SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 },
12227d299381SMarcus Cooper 	{ SUN8I_I2S_TX_CHAN_MAP_REG, 0x00000000 },
12237d299381SMarcus Cooper 	{ SUN8I_I2S_RX_CHAN_SEL_REG, 0x00000000 },
12247d299381SMarcus Cooper 	{ SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 },
12257d299381SMarcus Cooper };
12267d299381SMarcus Cooper 
122773adf87bSJernej Skrabec static const struct reg_default sun50i_h6_i2s_reg_defaults[] = {
122873adf87bSJernej Skrabec 	{ SUN4I_I2S_CTRL_REG, 0x00060000 },
122973adf87bSJernej Skrabec 	{ SUN4I_I2S_FMT0_REG, 0x00000033 },
123073adf87bSJernej Skrabec 	{ SUN4I_I2S_FMT1_REG, 0x00000030 },
123173adf87bSJernej Skrabec 	{ SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
123273adf87bSJernej Skrabec 	{ SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
123373adf87bSJernej Skrabec 	{ SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
123473adf87bSJernej Skrabec 	{ SUN8I_I2S_CHAN_CFG_REG, 0x00000000 },
1235c8bbc1deSSamuel Holland 	{ SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), 0x00000000 },
1236c8bbc1deSSamuel Holland 	{ SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0x00000000 },
1237c8bbc1deSSamuel Holland 	{ SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x00000000 },
123873adf87bSJernej Skrabec 	{ SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 },
123973adf87bSJernej Skrabec 	{ SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 },
124073adf87bSJernej Skrabec 	{ SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 },
124173adf87bSJernej Skrabec };
124273adf87bSJernej Skrabec 
1243fa7c0d13SMaxime Ripard static const struct regmap_config sun4i_i2s_regmap_config = {
1244fa7c0d13SMaxime Ripard 	.reg_bits	= 32,
1245fa7c0d13SMaxime Ripard 	.reg_stride	= 4,
1246fa7c0d13SMaxime Ripard 	.val_bits	= 32,
1247fa7c0d13SMaxime Ripard 	.max_register	= SUN4I_I2S_RX_CHAN_MAP_REG,
1248fa7c0d13SMaxime Ripard 
1249fa7c0d13SMaxime Ripard 	.cache_type	= REGCACHE_FLAT,
1250fa7c0d13SMaxime Ripard 	.reg_defaults	= sun4i_i2s_reg_defaults,
1251fa7c0d13SMaxime Ripard 	.num_reg_defaults	= ARRAY_SIZE(sun4i_i2s_reg_defaults),
1252fa7c0d13SMaxime Ripard 	.writeable_reg	= sun4i_i2s_wr_reg,
1253fa7c0d13SMaxime Ripard 	.readable_reg	= sun4i_i2s_rd_reg,
1254fa7c0d13SMaxime Ripard 	.volatile_reg	= sun4i_i2s_volatile_reg,
1255fa7c0d13SMaxime Ripard };
1256fa7c0d13SMaxime Ripard 
12577d299381SMarcus Cooper static const struct regmap_config sun8i_i2s_regmap_config = {
12587d299381SMarcus Cooper 	.reg_bits	= 32,
12597d299381SMarcus Cooper 	.reg_stride	= 4,
12607d299381SMarcus Cooper 	.val_bits	= 32,
12617d299381SMarcus Cooper 	.max_register	= SUN8I_I2S_RX_CHAN_MAP_REG,
12627d299381SMarcus Cooper 	.cache_type	= REGCACHE_FLAT,
12637d299381SMarcus Cooper 	.reg_defaults	= sun8i_i2s_reg_defaults,
12647d299381SMarcus Cooper 	.num_reg_defaults	= ARRAY_SIZE(sun8i_i2s_reg_defaults),
12657d299381SMarcus Cooper 	.writeable_reg	= sun4i_i2s_wr_reg,
12667d299381SMarcus Cooper 	.readable_reg	= sun8i_i2s_rd_reg,
12677d299381SMarcus Cooper 	.volatile_reg	= sun8i_i2s_volatile_reg,
12687d299381SMarcus Cooper };
12697d299381SMarcus Cooper 
127073adf87bSJernej Skrabec static const struct regmap_config sun50i_h6_i2s_regmap_config = {
127173adf87bSJernej Skrabec 	.reg_bits	= 32,
127273adf87bSJernej Skrabec 	.reg_stride	= 4,
127373adf87bSJernej Skrabec 	.val_bits	= 32,
1274e2ce580fSSamuel Holland 	.max_register	= SUN50I_R329_I2S_RX_CHAN_MAP3_REG,
127573adf87bSJernej Skrabec 	.cache_type	= REGCACHE_FLAT,
127673adf87bSJernej Skrabec 	.reg_defaults	= sun50i_h6_i2s_reg_defaults,
127773adf87bSJernej Skrabec 	.num_reg_defaults	= ARRAY_SIZE(sun50i_h6_i2s_reg_defaults),
127873adf87bSJernej Skrabec 	.writeable_reg	= sun4i_i2s_wr_reg,
127973adf87bSJernej Skrabec 	.readable_reg	= sun8i_i2s_rd_reg,
128073adf87bSJernej Skrabec 	.volatile_reg	= sun8i_i2s_volatile_reg,
128173adf87bSJernej Skrabec };
128273adf87bSJernej Skrabec 
sun4i_i2s_runtime_resume(struct device * dev)1283fa7c0d13SMaxime Ripard static int sun4i_i2s_runtime_resume(struct device *dev)
1284fa7c0d13SMaxime Ripard {
1285fa7c0d13SMaxime Ripard 	struct sun4i_i2s *i2s = dev_get_drvdata(dev);
1286fa7c0d13SMaxime Ripard 	int ret;
1287fa7c0d13SMaxime Ripard 
1288fa7c0d13SMaxime Ripard 	ret = clk_prepare_enable(i2s->bus_clk);
1289fa7c0d13SMaxime Ripard 	if (ret) {
1290fa7c0d13SMaxime Ripard 		dev_err(dev, "Failed to enable bus clock\n");
1291fa7c0d13SMaxime Ripard 		return ret;
1292fa7c0d13SMaxime Ripard 	}
1293fa7c0d13SMaxime Ripard 
1294fa7c0d13SMaxime Ripard 	regcache_cache_only(i2s->regmap, false);
1295fa7c0d13SMaxime Ripard 	regcache_mark_dirty(i2s->regmap);
1296fa7c0d13SMaxime Ripard 
1297fa7c0d13SMaxime Ripard 	ret = regcache_sync(i2s->regmap);
1298fa7c0d13SMaxime Ripard 	if (ret) {
1299fa7c0d13SMaxime Ripard 		dev_err(dev, "Failed to sync regmap cache\n");
1300fa7c0d13SMaxime Ripard 		goto err_disable_clk;
1301fa7c0d13SMaxime Ripard 	}
1302fa7c0d13SMaxime Ripard 
13037f91e2afSVasily Khoruzhick 	/* Enable the whole hardware block */
13047f91e2afSVasily Khoruzhick 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
13057f91e2afSVasily Khoruzhick 			   SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN);
13067f91e2afSVasily Khoruzhick 
13077f91e2afSVasily Khoruzhick 	/* Enable the first output line */
13087f91e2afSVasily Khoruzhick 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
13097f91e2afSVasily Khoruzhick 			   SUN4I_I2S_CTRL_SDO_EN_MASK,
13107f91e2afSVasily Khoruzhick 			   SUN4I_I2S_CTRL_SDO_EN(0));
13117f91e2afSVasily Khoruzhick 
13127f91e2afSVasily Khoruzhick 	ret = clk_prepare_enable(i2s->mod_clk);
13137f91e2afSVasily Khoruzhick 	if (ret) {
13147f91e2afSVasily Khoruzhick 		dev_err(dev, "Failed to enable module clock\n");
13157f91e2afSVasily Khoruzhick 		goto err_disable_clk;
13167f91e2afSVasily Khoruzhick 	}
13177f91e2afSVasily Khoruzhick 
1318fa7c0d13SMaxime Ripard 	return 0;
1319fa7c0d13SMaxime Ripard 
1320fa7c0d13SMaxime Ripard err_disable_clk:
1321fa7c0d13SMaxime Ripard 	clk_disable_unprepare(i2s->bus_clk);
1322fa7c0d13SMaxime Ripard 	return ret;
1323fa7c0d13SMaxime Ripard }
1324fa7c0d13SMaxime Ripard 
sun4i_i2s_runtime_suspend(struct device * dev)1325fa7c0d13SMaxime Ripard static int sun4i_i2s_runtime_suspend(struct device *dev)
1326fa7c0d13SMaxime Ripard {
1327fa7c0d13SMaxime Ripard 	struct sun4i_i2s *i2s = dev_get_drvdata(dev);
1328fa7c0d13SMaxime Ripard 
13297f91e2afSVasily Khoruzhick 	clk_disable_unprepare(i2s->mod_clk);
13307f91e2afSVasily Khoruzhick 
13317f91e2afSVasily Khoruzhick 	/* Disable our output lines */
13327f91e2afSVasily Khoruzhick 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
13337f91e2afSVasily Khoruzhick 			   SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
13347f91e2afSVasily Khoruzhick 
13357f91e2afSVasily Khoruzhick 	/* Disable the whole hardware block */
13367f91e2afSVasily Khoruzhick 	regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
13377f91e2afSVasily Khoruzhick 			   SUN4I_I2S_CTRL_GL_EN, 0);
13387f91e2afSVasily Khoruzhick 
1339fa7c0d13SMaxime Ripard 	regcache_cache_only(i2s->regmap, true);
1340fa7c0d13SMaxime Ripard 
1341fa7c0d13SMaxime Ripard 	clk_disable_unprepare(i2s->bus_clk);
1342fa7c0d13SMaxime Ripard 
1343fa7c0d13SMaxime Ripard 	return 0;
1344fa7c0d13SMaxime Ripard }
1345fa7c0d13SMaxime Ripard 
13462ad6f30dSMylène Josserand static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
13472ad6f30dSMylène Josserand 	.has_reset		= false,
13483509476eSMarcus Cooper 	.reg_offset_txdata	= SUN4I_I2S_FIFO_TX_REG,
1349cd1c63dfSMarcus Cooper 	.sun4i_i2s_regmap	= &sun4i_i2s_regmap_config,
13505f93b063SMarcus Cooper 	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
135177164715SMarcus Cooper 	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
135277164715SMarcus Cooper 	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
1353c1d3a921SMaxime Ripard 	.bclk_dividers		= sun4i_i2s_bclk_div,
1354c1d3a921SMaxime Ripard 	.num_bclk_dividers	= ARRAY_SIZE(sun4i_i2s_bclk_div),
1355c1d3a921SMaxime Ripard 	.mclk_dividers		= sun4i_i2s_mclk_div,
1356c1d3a921SMaxime Ripard 	.num_mclk_dividers	= ARRAY_SIZE(sun4i_i2s_mclk_div),
1357fb19739dSMaxime Ripard 	.get_bclk_parent_rate	= sun4i_i2s_get_bclk_parent_rate,
1358619c15f7SMaxime Ripard 	.get_sr			= sun4i_i2s_get_sr,
1359619c15f7SMaxime Ripard 	.get_wss		= sun4i_i2s_get_wss,
1360d70be625SMaxime Ripard 	.set_chan_cfg		= sun4i_i2s_set_chan_cfg,
136171137bcdSMaxime Ripard 	.set_fmt		= sun4i_i2s_set_soc_fmt,
13622ad6f30dSMylène Josserand };
13632ad6f30dSMylène Josserand 
13642ad6f30dSMylène Josserand static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
13652ad6f30dSMylène Josserand 	.has_reset		= true,
13663509476eSMarcus Cooper 	.reg_offset_txdata	= SUN4I_I2S_FIFO_TX_REG,
1367cd1c63dfSMarcus Cooper 	.sun4i_i2s_regmap	= &sun4i_i2s_regmap_config,
13685f93b063SMarcus Cooper 	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
136977164715SMarcus Cooper 	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
137077164715SMarcus Cooper 	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
1371c1d3a921SMaxime Ripard 	.bclk_dividers		= sun4i_i2s_bclk_div,
1372c1d3a921SMaxime Ripard 	.num_bclk_dividers	= ARRAY_SIZE(sun4i_i2s_bclk_div),
1373c1d3a921SMaxime Ripard 	.mclk_dividers		= sun4i_i2s_mclk_div,
1374c1d3a921SMaxime Ripard 	.num_mclk_dividers	= ARRAY_SIZE(sun4i_i2s_mclk_div),
1375fb19739dSMaxime Ripard 	.get_bclk_parent_rate	= sun4i_i2s_get_bclk_parent_rate,
1376619c15f7SMaxime Ripard 	.get_sr			= sun4i_i2s_get_sr,
1377619c15f7SMaxime Ripard 	.get_wss		= sun4i_i2s_get_wss,
1378d70be625SMaxime Ripard 	.set_chan_cfg		= sun4i_i2s_set_chan_cfg,
137971137bcdSMaxime Ripard 	.set_fmt		= sun4i_i2s_set_soc_fmt,
13802ad6f30dSMylène Josserand };
13812ad6f30dSMylène Josserand 
1382455b1d42SMaxime Ripard /*
1383455b1d42SMaxime Ripard  * This doesn't describe the TDM controller documented in the A83t
1384455b1d42SMaxime Ripard  * datasheet, but the three undocumented I2S controller that use the
1385455b1d42SMaxime Ripard  * older design.
1386455b1d42SMaxime Ripard  */
138721faaea1SChen-Yu Tsai static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = {
138821faaea1SChen-Yu Tsai 	.has_reset		= true,
138921faaea1SChen-Yu Tsai 	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,
139021faaea1SChen-Yu Tsai 	.sun4i_i2s_regmap	= &sun4i_i2s_regmap_config,
13919ec05d47SMaxime Ripard 	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
13929ec05d47SMaxime Ripard 	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
13939ec05d47SMaxime Ripard 	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
13949ec05d47SMaxime Ripard 	.bclk_dividers		= sun4i_i2s_bclk_div,
13959ec05d47SMaxime Ripard 	.num_bclk_dividers	= ARRAY_SIZE(sun4i_i2s_bclk_div),
13969ec05d47SMaxime Ripard 	.mclk_dividers		= sun4i_i2s_mclk_div,
13979ec05d47SMaxime Ripard 	.num_mclk_dividers	= ARRAY_SIZE(sun4i_i2s_mclk_div),
13989ec05d47SMaxime Ripard 	.get_bclk_parent_rate	= sun4i_i2s_get_bclk_parent_rate,
13999ec05d47SMaxime Ripard 	.get_sr			= sun4i_i2s_get_sr,
14009ec05d47SMaxime Ripard 	.get_wss		= sun4i_i2s_get_wss,
14019ec05d47SMaxime Ripard 	.set_chan_cfg		= sun4i_i2s_set_chan_cfg,
14029ec05d47SMaxime Ripard 	.set_fmt		= sun4i_i2s_set_soc_fmt,
140321faaea1SChen-Yu Tsai };
140421faaea1SChen-Yu Tsai 
1405455b1d42SMaxime Ripard static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = {
1406455b1d42SMaxime Ripard 	.has_reset		= true,
1407455b1d42SMaxime Ripard 	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,
1408455b1d42SMaxime Ripard 	.sun4i_i2s_regmap	= &sun8i_i2s_regmap_config,
1409455b1d42SMaxime Ripard 	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
1410455b1d42SMaxime Ripard 	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
1411455b1d42SMaxime Ripard 	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
1412455b1d42SMaxime Ripard 	.bclk_dividers		= sun8i_i2s_clk_div,
1413455b1d42SMaxime Ripard 	.num_bclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),
1414455b1d42SMaxime Ripard 	.mclk_dividers		= sun8i_i2s_clk_div,
1415455b1d42SMaxime Ripard 	.num_mclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),
1416455b1d42SMaxime Ripard 	.get_bclk_parent_rate	= sun8i_i2s_get_bclk_parent_rate,
1417455b1d42SMaxime Ripard 	.get_sr			= sun8i_i2s_get_sr_wss,
1418455b1d42SMaxime Ripard 	.get_wss		= sun8i_i2s_get_sr_wss,
1419455b1d42SMaxime Ripard 	.set_chan_cfg		= sun8i_i2s_set_chan_cfg,
1420455b1d42SMaxime Ripard 	.set_fmt		= sun8i_i2s_set_soc_fmt,
1421455b1d42SMaxime Ripard };
1422455b1d42SMaxime Ripard 
142366ecce33SMarcus Cooper static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = {
142466ecce33SMarcus Cooper 	.has_reset		= true,
142566ecce33SMarcus Cooper 	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,
142666ecce33SMarcus Cooper 	.sun4i_i2s_regmap	= &sun4i_i2s_regmap_config,
142766ecce33SMarcus Cooper 	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7),
142866ecce33SMarcus Cooper 	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3),
142966ecce33SMarcus Cooper 	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5),
1430c1d3a921SMaxime Ripard 	.bclk_dividers		= sun4i_i2s_bclk_div,
1431c1d3a921SMaxime Ripard 	.num_bclk_dividers	= ARRAY_SIZE(sun4i_i2s_bclk_div),
1432c1d3a921SMaxime Ripard 	.mclk_dividers		= sun4i_i2s_mclk_div,
1433c1d3a921SMaxime Ripard 	.num_mclk_dividers	= ARRAY_SIZE(sun4i_i2s_mclk_div),
1434fb19739dSMaxime Ripard 	.get_bclk_parent_rate	= sun4i_i2s_get_bclk_parent_rate,
143552f87f3cSMarcus Cooper 	.get_sr			= sun4i_i2s_get_sr,
143652f87f3cSMarcus Cooper 	.get_wss		= sun4i_i2s_get_wss,
1437d70be625SMaxime Ripard 	.set_chan_cfg		= sun4i_i2s_set_chan_cfg,
143871137bcdSMaxime Ripard 	.set_fmt		= sun4i_i2s_set_soc_fmt,
143966ecce33SMarcus Cooper };
144066ecce33SMarcus Cooper 
144173adf87bSJernej Skrabec static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = {
144273adf87bSJernej Skrabec 	.has_reset		= true,
144373adf87bSJernej Skrabec 	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,
144473adf87bSJernej Skrabec 	.sun4i_i2s_regmap	= &sun50i_h6_i2s_regmap_config,
144573adf87bSJernej Skrabec 	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
144673adf87bSJernej Skrabec 	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
144773adf87bSJernej Skrabec 	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
144873adf87bSJernej Skrabec 	.bclk_dividers		= sun8i_i2s_clk_div,
144973adf87bSJernej Skrabec 	.num_bclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),
145073adf87bSJernej Skrabec 	.mclk_dividers		= sun8i_i2s_clk_div,
145173adf87bSJernej Skrabec 	.num_mclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),
145273adf87bSJernej Skrabec 	.get_bclk_parent_rate	= sun8i_i2s_get_bclk_parent_rate,
145373adf87bSJernej Skrabec 	.get_sr			= sun8i_i2s_get_sr_wss,
145473adf87bSJernej Skrabec 	.get_wss		= sun8i_i2s_get_sr_wss,
145573adf87bSJernej Skrabec 	.set_chan_cfg		= sun50i_h6_i2s_set_chan_cfg,
145673adf87bSJernej Skrabec 	.set_fmt		= sun50i_h6_i2s_set_soc_fmt,
145773adf87bSJernej Skrabec };
145873adf87bSJernej Skrabec 
1459e2ce580fSSamuel Holland static const struct sun4i_i2s_quirks sun50i_r329_i2s_quirks = {
1460e2ce580fSSamuel Holland 	.has_reset		= true,
1461e2ce580fSSamuel Holland 	.reg_offset_txdata	= SUN8I_I2S_FIFO_TX_REG,
1462e2ce580fSSamuel Holland 	.sun4i_i2s_regmap	= &sun50i_h6_i2s_regmap_config,
1463e2ce580fSSamuel Holland 	.field_clkdiv_mclk_en	= REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8),
1464e2ce580fSSamuel Holland 	.field_fmt_wss		= REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2),
1465e2ce580fSSamuel Holland 	.field_fmt_sr		= REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6),
1466e2ce580fSSamuel Holland 	.num_din_pins		= 4,
1467e2ce580fSSamuel Holland 	.num_dout_pins		= 4,
1468e2ce580fSSamuel Holland 	.bclk_dividers		= sun8i_i2s_clk_div,
1469e2ce580fSSamuel Holland 	.num_bclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),
1470e2ce580fSSamuel Holland 	.mclk_dividers		= sun8i_i2s_clk_div,
1471e2ce580fSSamuel Holland 	.num_mclk_dividers	= ARRAY_SIZE(sun8i_i2s_clk_div),
1472e2ce580fSSamuel Holland 	.get_bclk_parent_rate	= sun8i_i2s_get_bclk_parent_rate,
1473e2ce580fSSamuel Holland 	.get_sr			= sun8i_i2s_get_sr_wss,
1474e2ce580fSSamuel Holland 	.get_wss		= sun8i_i2s_get_sr_wss,
1475e2ce580fSSamuel Holland 	.set_chan_cfg		= sun50i_h6_i2s_set_chan_cfg,
1476e2ce580fSSamuel Holland 	.set_fmt		= sun50i_h6_i2s_set_soc_fmt,
1477e2ce580fSSamuel Holland };
1478e2ce580fSSamuel Holland 
sun4i_i2s_init_regmap_fields(struct device * dev,struct sun4i_i2s * i2s)14796eb4f274SMarcus Cooper static int sun4i_i2s_init_regmap_fields(struct device *dev,
14806eb4f274SMarcus Cooper 					struct sun4i_i2s *i2s)
14816eb4f274SMarcus Cooper {
14825f93b063SMarcus Cooper 	i2s->field_clkdiv_mclk_en =
14835f93b063SMarcus Cooper 		devm_regmap_field_alloc(dev, i2s->regmap,
14845f93b063SMarcus Cooper 					i2s->variant->field_clkdiv_mclk_en);
14855f93b063SMarcus Cooper 	if (IS_ERR(i2s->field_clkdiv_mclk_en))
14865f93b063SMarcus Cooper 		return PTR_ERR(i2s->field_clkdiv_mclk_en);
14875f93b063SMarcus Cooper 
148877164715SMarcus Cooper 	i2s->field_fmt_wss =
148977164715SMarcus Cooper 			devm_regmap_field_alloc(dev, i2s->regmap,
149077164715SMarcus Cooper 						i2s->variant->field_fmt_wss);
149177164715SMarcus Cooper 	if (IS_ERR(i2s->field_fmt_wss))
149277164715SMarcus Cooper 		return PTR_ERR(i2s->field_fmt_wss);
149377164715SMarcus Cooper 
149477164715SMarcus Cooper 	i2s->field_fmt_sr =
149577164715SMarcus Cooper 			devm_regmap_field_alloc(dev, i2s->regmap,
149677164715SMarcus Cooper 						i2s->variant->field_fmt_sr);
149777164715SMarcus Cooper 	if (IS_ERR(i2s->field_fmt_sr))
149877164715SMarcus Cooper 		return PTR_ERR(i2s->field_fmt_sr);
149977164715SMarcus Cooper 
1500d70be625SMaxime Ripard 	return 0;
15016eb4f274SMarcus Cooper }
15026eb4f274SMarcus Cooper 
sun4i_i2s_probe(struct platform_device * pdev)1503fa7c0d13SMaxime Ripard static int sun4i_i2s_probe(struct platform_device *pdev)
1504fa7c0d13SMaxime Ripard {
1505fa7c0d13SMaxime Ripard 	struct sun4i_i2s *i2s;
1506fa7c0d13SMaxime Ripard 	struct resource *res;
1507fa7c0d13SMaxime Ripard 	void __iomem *regs;
1508fa7c0d13SMaxime Ripard 	int irq, ret;
1509fa7c0d13SMaxime Ripard 
1510fa7c0d13SMaxime Ripard 	i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
1511fa7c0d13SMaxime Ripard 	if (!i2s)
1512fa7c0d13SMaxime Ripard 		return -ENOMEM;
1513fa7c0d13SMaxime Ripard 	platform_set_drvdata(pdev, i2s);
1514fa7c0d13SMaxime Ripard 
1515cc384f05SYang Yingliang 	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
151662ee4ecbSWei Yongjun 	if (IS_ERR(regs))
1517fa7c0d13SMaxime Ripard 		return PTR_ERR(regs);
1518fa7c0d13SMaxime Ripard 
1519fa7c0d13SMaxime Ripard 	irq = platform_get_irq(pdev, 0);
1520cf9441adSStephen Boyd 	if (irq < 0)
1521fa7c0d13SMaxime Ripard 		return irq;
1522fa7c0d13SMaxime Ripard 
152347bea0c8SMarcus Cooper 	i2s->variant = of_device_get_match_data(&pdev->dev);
152447bea0c8SMarcus Cooper 	if (!i2s->variant) {
15252ad6f30dSMylène Josserand 		dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
15262ad6f30dSMylène Josserand 		return -ENODEV;
15272ad6f30dSMylène Josserand 	}
15282ad6f30dSMylène Josserand 
1529fa7c0d13SMaxime Ripard 	i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");
1530fa7c0d13SMaxime Ripard 	if (IS_ERR(i2s->bus_clk)) {
1531fa7c0d13SMaxime Ripard 		dev_err(&pdev->dev, "Can't get our bus clock\n");
1532fa7c0d13SMaxime Ripard 		return PTR_ERR(i2s->bus_clk);
1533fa7c0d13SMaxime Ripard 	}
1534fa7c0d13SMaxime Ripard 
1535fa7c0d13SMaxime Ripard 	i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
1536cd1c63dfSMarcus Cooper 					    i2s->variant->sun4i_i2s_regmap);
1537fa7c0d13SMaxime Ripard 	if (IS_ERR(i2s->regmap)) {
1538fa7c0d13SMaxime Ripard 		dev_err(&pdev->dev, "Regmap initialisation failed\n");
1539fa7c0d13SMaxime Ripard 		return PTR_ERR(i2s->regmap);
1540dcf7d199Skbuild test robot 	}
1541fa7c0d13SMaxime Ripard 
1542fa7c0d13SMaxime Ripard 	i2s->mod_clk = devm_clk_get(&pdev->dev, "mod");
1543fa7c0d13SMaxime Ripard 	if (IS_ERR(i2s->mod_clk)) {
1544fa7c0d13SMaxime Ripard 		dev_err(&pdev->dev, "Can't get our mod clock\n");
1545fa7c0d13SMaxime Ripard 		return PTR_ERR(i2s->mod_clk);
1546fa7c0d13SMaxime Ripard 	}
1547fa7c0d13SMaxime Ripard 
154847bea0c8SMarcus Cooper 	if (i2s->variant->has_reset) {
154972bfa211SPhilipp Zabel 		i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
15502ad6f30dSMylène Josserand 		if (IS_ERR(i2s->rst)) {
15512ad6f30dSMylène Josserand 			dev_err(&pdev->dev, "Failed to get reset control\n");
15522ad6f30dSMylène Josserand 			return PTR_ERR(i2s->rst);
15532ad6f30dSMylène Josserand 		}
15542ad6f30dSMylène Josserand 	}
15552ad6f30dSMylène Josserand 
15562ad6f30dSMylène Josserand 	if (!IS_ERR(i2s->rst)) {
15572ad6f30dSMylène Josserand 		ret = reset_control_deassert(i2s->rst);
15582ad6f30dSMylène Josserand 		if (ret) {
15592ad6f30dSMylène Josserand 			dev_err(&pdev->dev,
15602ad6f30dSMylène Josserand 				"Failed to deassert the reset control\n");
15612ad6f30dSMylène Josserand 			return -EINVAL;
15622ad6f30dSMylène Josserand 		}
15632ad6f30dSMylène Josserand 	}
15642ad6f30dSMylène Josserand 
15653509476eSMarcus Cooper 	i2s->playback_dma_data.addr = res->start +
15663509476eSMarcus Cooper 					i2s->variant->reg_offset_txdata;
1567ebad64d1SMylène Josserand 	i2s->playback_dma_data.maxburst = 8;
1568fa7c0d13SMaxime Ripard 
1569ae73b34fSMaxime Ripard 	i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
1570ebad64d1SMylène Josserand 	i2s->capture_dma_data.maxburst = 8;
1571ae73b34fSMaxime Ripard 
1572fa7c0d13SMaxime Ripard 	pm_runtime_enable(&pdev->dev);
1573fa7c0d13SMaxime Ripard 	if (!pm_runtime_enabled(&pdev->dev)) {
1574fa7c0d13SMaxime Ripard 		ret = sun4i_i2s_runtime_resume(&pdev->dev);
1575fa7c0d13SMaxime Ripard 		if (ret)
1576fa7c0d13SMaxime Ripard 			goto err_pm_disable;
1577fa7c0d13SMaxime Ripard 	}
1578fa7c0d13SMaxime Ripard 
1579bf283a05SMaxime Ripard 	ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s);
1580fa7c0d13SMaxime Ripard 	if (ret) {
1581bf283a05SMaxime Ripard 		dev_err(&pdev->dev, "Could not initialise regmap fields\n");
1582fa7c0d13SMaxime Ripard 		goto err_suspend;
1583fa7c0d13SMaxime Ripard 	}
1584fa7c0d13SMaxime Ripard 
1585a49d24e7SMaxime Ripard 	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
1586fa7c0d13SMaxime Ripard 	if (ret) {
1587fa7c0d13SMaxime Ripard 		dev_err(&pdev->dev, "Could not register PCM\n");
1588fa7c0d13SMaxime Ripard 		goto err_suspend;
1589fa7c0d13SMaxime Ripard 	}
1590fa7c0d13SMaxime Ripard 
1591bf283a05SMaxime Ripard 	ret = devm_snd_soc_register_component(&pdev->dev,
1592bf283a05SMaxime Ripard 					      &sun4i_i2s_component,
1593bf283a05SMaxime Ripard 					      &sun4i_i2s_dai, 1);
15946eb4f274SMarcus Cooper 	if (ret) {
1595bf283a05SMaxime Ripard 		dev_err(&pdev->dev, "Could not register DAI\n");
15966eb4f274SMarcus Cooper 		goto err_suspend;
15976eb4f274SMarcus Cooper 	}
15986eb4f274SMarcus Cooper 
1599fa7c0d13SMaxime Ripard 	return 0;
1600fa7c0d13SMaxime Ripard 
1601fa7c0d13SMaxime Ripard err_suspend:
1602fa7c0d13SMaxime Ripard 	if (!pm_runtime_status_suspended(&pdev->dev))
1603fa7c0d13SMaxime Ripard 		sun4i_i2s_runtime_suspend(&pdev->dev);
1604fa7c0d13SMaxime Ripard err_pm_disable:
1605fa7c0d13SMaxime Ripard 	pm_runtime_disable(&pdev->dev);
16062ad6f30dSMylène Josserand 	if (!IS_ERR(i2s->rst))
16072ad6f30dSMylène Josserand 		reset_control_assert(i2s->rst);
1608fa7c0d13SMaxime Ripard 
1609fa7c0d13SMaxime Ripard 	return ret;
1610fa7c0d13SMaxime Ripard }
1611fa7c0d13SMaxime Ripard 
sun4i_i2s_remove(struct platform_device * pdev)16125423c00eSUwe Kleine-König static void sun4i_i2s_remove(struct platform_device *pdev)
1613fa7c0d13SMaxime Ripard {
16142ad6f30dSMylène Josserand 	struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev);
16152ad6f30dSMylène Josserand 
1616fa7c0d13SMaxime Ripard 	pm_runtime_disable(&pdev->dev);
1617fa7c0d13SMaxime Ripard 	if (!pm_runtime_status_suspended(&pdev->dev))
1618fa7c0d13SMaxime Ripard 		sun4i_i2s_runtime_suspend(&pdev->dev);
1619fa7c0d13SMaxime Ripard 
16202ad6f30dSMylène Josserand 	if (!IS_ERR(i2s->rst))
16212ad6f30dSMylène Josserand 		reset_control_assert(i2s->rst);
1622fa7c0d13SMaxime Ripard }
1623fa7c0d13SMaxime Ripard 
1624fa7c0d13SMaxime Ripard static const struct of_device_id sun4i_i2s_match[] = {
16252ad6f30dSMylène Josserand 	{
16262ad6f30dSMylène Josserand 		.compatible = "allwinner,sun4i-a10-i2s",
16272ad6f30dSMylène Josserand 		.data = &sun4i_a10_i2s_quirks,
16282ad6f30dSMylène Josserand 	},
16292ad6f30dSMylène Josserand 	{
16302ad6f30dSMylène Josserand 		.compatible = "allwinner,sun6i-a31-i2s",
16312ad6f30dSMylène Josserand 		.data = &sun6i_a31_i2s_quirks,
16322ad6f30dSMylène Josserand 	},
16337d299381SMarcus Cooper 	{
163421faaea1SChen-Yu Tsai 		.compatible = "allwinner,sun8i-a83t-i2s",
163521faaea1SChen-Yu Tsai 		.data = &sun8i_a83t_i2s_quirks,
163621faaea1SChen-Yu Tsai 	},
163721faaea1SChen-Yu Tsai 	{
16387d299381SMarcus Cooper 		.compatible = "allwinner,sun8i-h3-i2s",
1639455b1d42SMaxime Ripard 		.data = &sun8i_h3_i2s_quirks,
16407d299381SMarcus Cooper 	},
164166ecce33SMarcus Cooper 	{
164266ecce33SMarcus Cooper 		.compatible = "allwinner,sun50i-a64-codec-i2s",
164366ecce33SMarcus Cooper 		.data = &sun50i_a64_codec_i2s_quirks,
164466ecce33SMarcus Cooper 	},
164573adf87bSJernej Skrabec 	{
164673adf87bSJernej Skrabec 		.compatible = "allwinner,sun50i-h6-i2s",
164773adf87bSJernej Skrabec 		.data = &sun50i_h6_i2s_quirks,
164873adf87bSJernej Skrabec 	},
1649e2ce580fSSamuel Holland 	{
1650e2ce580fSSamuel Holland 		.compatible = "allwinner,sun50i-r329-i2s",
1651e2ce580fSSamuel Holland 		.data = &sun50i_r329_i2s_quirks,
1652e2ce580fSSamuel Holland 	},
1653fa7c0d13SMaxime Ripard 	{}
1654fa7c0d13SMaxime Ripard };
1655fa7c0d13SMaxime Ripard MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
1656fa7c0d13SMaxime Ripard 
1657fa7c0d13SMaxime Ripard static const struct dev_pm_ops sun4i_i2s_pm_ops = {
1658fa7c0d13SMaxime Ripard 	.runtime_resume		= sun4i_i2s_runtime_resume,
1659fa7c0d13SMaxime Ripard 	.runtime_suspend	= sun4i_i2s_runtime_suspend,
1660fa7c0d13SMaxime Ripard };
1661fa7c0d13SMaxime Ripard 
1662fa7c0d13SMaxime Ripard static struct platform_driver sun4i_i2s_driver = {
1663fa7c0d13SMaxime Ripard 	.probe	= sun4i_i2s_probe,
16645423c00eSUwe Kleine-König 	.remove_new = sun4i_i2s_remove,
1665fa7c0d13SMaxime Ripard 	.driver	= {
1666fa7c0d13SMaxime Ripard 		.name		= "sun4i-i2s",
1667fa7c0d13SMaxime Ripard 		.of_match_table	= sun4i_i2s_match,
1668fa7c0d13SMaxime Ripard 		.pm		= &sun4i_i2s_pm_ops,
1669fa7c0d13SMaxime Ripard 	},
1670fa7c0d13SMaxime Ripard };
1671fa7c0d13SMaxime Ripard module_platform_driver(sun4i_i2s_driver);
1672fa7c0d13SMaxime Ripard 
1673fa7c0d13SMaxime Ripard MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
1674fa7c0d13SMaxime Ripard MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1675fa7c0d13SMaxime Ripard MODULE_DESCRIPTION("Allwinner A10 I2S driver");
1676fa7c0d13SMaxime Ripard MODULE_LICENSE("GPL");
1677