xref: /OK3568_Linux_fs/kernel/sound/soc/stm/stm32_sai_sub.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
6*4882a593Smuzhiyun  * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/clk.h>
10*4882a593Smuzhiyun #include <linux/clk-provider.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/of_irq.h>
14*4882a593Smuzhiyun #include <linux/of_platform.h>
15*4882a593Smuzhiyun #include <linux/pm_runtime.h>
16*4882a593Smuzhiyun #include <linux/regmap.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <sound/asoundef.h>
19*4882a593Smuzhiyun #include <sound/core.h>
20*4882a593Smuzhiyun #include <sound/dmaengine_pcm.h>
21*4882a593Smuzhiyun #include <sound/pcm_params.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include "stm32_sai.h"
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define SAI_FREE_PROTOCOL	0x0
26*4882a593Smuzhiyun #define SAI_SPDIF_PROTOCOL	0x1
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define SAI_SLOT_SIZE_AUTO	0x0
29*4882a593Smuzhiyun #define SAI_SLOT_SIZE_16	0x1
30*4882a593Smuzhiyun #define SAI_SLOT_SIZE_32	0x2
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #define SAI_DATASIZE_8		0x2
33*4882a593Smuzhiyun #define SAI_DATASIZE_10		0x3
34*4882a593Smuzhiyun #define SAI_DATASIZE_16		0x4
35*4882a593Smuzhiyun #define SAI_DATASIZE_20		0x5
36*4882a593Smuzhiyun #define SAI_DATASIZE_24		0x6
37*4882a593Smuzhiyun #define SAI_DATASIZE_32		0x7
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define STM_SAI_DAI_NAME_SIZE	15
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #define STM_SAI_IS_PLAYBACK(ip)	((ip)->dir == SNDRV_PCM_STREAM_PLAYBACK)
42*4882a593Smuzhiyun #define STM_SAI_IS_CAPTURE(ip)	((ip)->dir == SNDRV_PCM_STREAM_CAPTURE)
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #define STM_SAI_A_ID		0x0
45*4882a593Smuzhiyun #define STM_SAI_B_ID		0x1
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define STM_SAI_IS_SUB_A(x)	((x)->id == STM_SAI_A_ID)
48*4882a593Smuzhiyun #define STM_SAI_IS_SUB_B(x)	((x)->id == STM_SAI_B_ID)
49*4882a593Smuzhiyun #define STM_SAI_BLOCK_NAME(x)	(((x)->id == STM_SAI_A_ID) ? "A" : "B")
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #define SAI_SYNC_NONE		0x0
52*4882a593Smuzhiyun #define SAI_SYNC_INTERNAL	0x1
53*4882a593Smuzhiyun #define SAI_SYNC_EXTERNAL	0x2
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define STM_SAI_PROTOCOL_IS_SPDIF(ip)	((ip)->spdif)
56*4882a593Smuzhiyun #define STM_SAI_HAS_SPDIF(x)	((x)->pdata->conf.has_spdif_pdm)
57*4882a593Smuzhiyun #define STM_SAI_HAS_PDM(x)	((x)->pdata->conf.has_spdif_pdm)
58*4882a593Smuzhiyun #define STM_SAI_HAS_EXT_SYNC(x) (!STM_SAI_IS_F4(sai->pdata))
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define SAI_IEC60958_BLOCK_FRAMES	192
61*4882a593Smuzhiyun #define SAI_IEC60958_STATUS_BYTES	24
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #define SAI_MCLK_NAME_LEN		32
64*4882a593Smuzhiyun #define SAI_RATE_11K			11025
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /**
67*4882a593Smuzhiyun  * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
68*4882a593Smuzhiyun  * @pdev: device data pointer
69*4882a593Smuzhiyun  * @regmap: SAI register map pointer
70*4882a593Smuzhiyun  * @regmap_config: SAI sub block register map configuration pointer
71*4882a593Smuzhiyun  * @dma_params: dma configuration data for rx or tx channel
72*4882a593Smuzhiyun  * @cpu_dai_drv: DAI driver data pointer
73*4882a593Smuzhiyun  * @cpu_dai: DAI runtime data pointer
74*4882a593Smuzhiyun  * @substream: PCM substream data pointer
75*4882a593Smuzhiyun  * @pdata: SAI block parent data pointer
76*4882a593Smuzhiyun  * @np_sync_provider: synchronization provider node
77*4882a593Smuzhiyun  * @sai_ck: kernel clock feeding the SAI clock generator
78*4882a593Smuzhiyun  * @sai_mclk: master clock from SAI mclk provider
79*4882a593Smuzhiyun  * @phys_addr: SAI registers physical base address
80*4882a593Smuzhiyun  * @mclk_rate: SAI block master clock frequency (Hz). set at init
81*4882a593Smuzhiyun  * @id: SAI sub block id corresponding to sub-block A or B
82*4882a593Smuzhiyun  * @dir: SAI block direction (playback or capture). set at init
83*4882a593Smuzhiyun  * @master: SAI block mode flag. (true=master, false=slave) set at init
84*4882a593Smuzhiyun  * @spdif: SAI S/PDIF iec60958 mode flag. set at init
85*4882a593Smuzhiyun  * @fmt: SAI block format. relevant only for custom protocols. set at init
86*4882a593Smuzhiyun  * @sync: SAI block synchronization mode. (none, internal or external)
87*4882a593Smuzhiyun  * @synco: SAI block ext sync source (provider setting). (none, sub-block A/B)
88*4882a593Smuzhiyun  * @synci: SAI block ext sync source (client setting). (SAI sync provider index)
89*4882a593Smuzhiyun  * @fs_length: frame synchronization length. depends on protocol settings
90*4882a593Smuzhiyun  * @slots: rx or tx slot number
91*4882a593Smuzhiyun  * @slot_width: rx or tx slot width in bits
92*4882a593Smuzhiyun  * @slot_mask: rx or tx active slots mask. set at init or at runtime
93*4882a593Smuzhiyun  * @data_size: PCM data width. corresponds to PCM substream width.
94*4882a593Smuzhiyun  * @spdif_frm_cnt: S/PDIF playback frame counter
95*4882a593Smuzhiyun  * @iec958: iec958 data
96*4882a593Smuzhiyun  * @ctrl_lock: control lock
97*4882a593Smuzhiyun  * @irq_lock: prevent race condition with IRQ
98*4882a593Smuzhiyun  */
99*4882a593Smuzhiyun struct stm32_sai_sub_data {
100*4882a593Smuzhiyun 	struct platform_device *pdev;
101*4882a593Smuzhiyun 	struct regmap *regmap;
102*4882a593Smuzhiyun 	const struct regmap_config *regmap_config;
103*4882a593Smuzhiyun 	struct snd_dmaengine_dai_dma_data dma_params;
104*4882a593Smuzhiyun 	struct snd_soc_dai_driver cpu_dai_drv;
105*4882a593Smuzhiyun 	struct snd_soc_dai *cpu_dai;
106*4882a593Smuzhiyun 	struct snd_pcm_substream *substream;
107*4882a593Smuzhiyun 	struct stm32_sai_data *pdata;
108*4882a593Smuzhiyun 	struct device_node *np_sync_provider;
109*4882a593Smuzhiyun 	struct clk *sai_ck;
110*4882a593Smuzhiyun 	struct clk *sai_mclk;
111*4882a593Smuzhiyun 	dma_addr_t phys_addr;
112*4882a593Smuzhiyun 	unsigned int mclk_rate;
113*4882a593Smuzhiyun 	unsigned int id;
114*4882a593Smuzhiyun 	int dir;
115*4882a593Smuzhiyun 	bool master;
116*4882a593Smuzhiyun 	bool spdif;
117*4882a593Smuzhiyun 	int fmt;
118*4882a593Smuzhiyun 	int sync;
119*4882a593Smuzhiyun 	int synco;
120*4882a593Smuzhiyun 	int synci;
121*4882a593Smuzhiyun 	int fs_length;
122*4882a593Smuzhiyun 	int slots;
123*4882a593Smuzhiyun 	int slot_width;
124*4882a593Smuzhiyun 	int slot_mask;
125*4882a593Smuzhiyun 	int data_size;
126*4882a593Smuzhiyun 	unsigned int spdif_frm_cnt;
127*4882a593Smuzhiyun 	struct snd_aes_iec958 iec958;
128*4882a593Smuzhiyun 	struct mutex ctrl_lock; /* protect resources accessed by controls */
129*4882a593Smuzhiyun 	spinlock_t irq_lock; /* used to prevent race condition with IRQ */
130*4882a593Smuzhiyun };
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun enum stm32_sai_fifo_th {
133*4882a593Smuzhiyun 	STM_SAI_FIFO_TH_EMPTY,
134*4882a593Smuzhiyun 	STM_SAI_FIFO_TH_QUARTER,
135*4882a593Smuzhiyun 	STM_SAI_FIFO_TH_HALF,
136*4882a593Smuzhiyun 	STM_SAI_FIFO_TH_3_QUARTER,
137*4882a593Smuzhiyun 	STM_SAI_FIFO_TH_FULL,
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
stm32_sai_sub_readable_reg(struct device * dev,unsigned int reg)140*4882a593Smuzhiyun static bool stm32_sai_sub_readable_reg(struct device *dev, unsigned int reg)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	switch (reg) {
143*4882a593Smuzhiyun 	case STM_SAI_CR1_REGX:
144*4882a593Smuzhiyun 	case STM_SAI_CR2_REGX:
145*4882a593Smuzhiyun 	case STM_SAI_FRCR_REGX:
146*4882a593Smuzhiyun 	case STM_SAI_SLOTR_REGX:
147*4882a593Smuzhiyun 	case STM_SAI_IMR_REGX:
148*4882a593Smuzhiyun 	case STM_SAI_SR_REGX:
149*4882a593Smuzhiyun 	case STM_SAI_CLRFR_REGX:
150*4882a593Smuzhiyun 	case STM_SAI_DR_REGX:
151*4882a593Smuzhiyun 	case STM_SAI_PDMCR_REGX:
152*4882a593Smuzhiyun 	case STM_SAI_PDMLY_REGX:
153*4882a593Smuzhiyun 		return true;
154*4882a593Smuzhiyun 	default:
155*4882a593Smuzhiyun 		return false;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
stm32_sai_sub_volatile_reg(struct device * dev,unsigned int reg)159*4882a593Smuzhiyun static bool stm32_sai_sub_volatile_reg(struct device *dev, unsigned int reg)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	switch (reg) {
162*4882a593Smuzhiyun 	case STM_SAI_DR_REGX:
163*4882a593Smuzhiyun 	case STM_SAI_SR_REGX:
164*4882a593Smuzhiyun 		return true;
165*4882a593Smuzhiyun 	default:
166*4882a593Smuzhiyun 		return false;
167*4882a593Smuzhiyun 	}
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun 
stm32_sai_sub_writeable_reg(struct device * dev,unsigned int reg)170*4882a593Smuzhiyun static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	switch (reg) {
173*4882a593Smuzhiyun 	case STM_SAI_CR1_REGX:
174*4882a593Smuzhiyun 	case STM_SAI_CR2_REGX:
175*4882a593Smuzhiyun 	case STM_SAI_FRCR_REGX:
176*4882a593Smuzhiyun 	case STM_SAI_SLOTR_REGX:
177*4882a593Smuzhiyun 	case STM_SAI_IMR_REGX:
178*4882a593Smuzhiyun 	case STM_SAI_CLRFR_REGX:
179*4882a593Smuzhiyun 	case STM_SAI_DR_REGX:
180*4882a593Smuzhiyun 	case STM_SAI_PDMCR_REGX:
181*4882a593Smuzhiyun 	case STM_SAI_PDMLY_REGX:
182*4882a593Smuzhiyun 		return true;
183*4882a593Smuzhiyun 	default:
184*4882a593Smuzhiyun 		return false;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun 
stm32_sai_sub_reg_up(struct stm32_sai_sub_data * sai,unsigned int reg,unsigned int mask,unsigned int val)188*4882a593Smuzhiyun static int stm32_sai_sub_reg_up(struct stm32_sai_sub_data *sai,
189*4882a593Smuzhiyun 				unsigned int reg, unsigned int mask,
190*4882a593Smuzhiyun 				unsigned int val)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	int ret;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	ret = clk_enable(sai->pdata->pclk);
195*4882a593Smuzhiyun 	if (ret < 0)
196*4882a593Smuzhiyun 		return ret;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	ret = regmap_update_bits(sai->regmap, reg, mask, val);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	clk_disable(sai->pdata->pclk);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	return ret;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun 
stm32_sai_sub_reg_wr(struct stm32_sai_sub_data * sai,unsigned int reg,unsigned int mask,unsigned int val)205*4882a593Smuzhiyun static int stm32_sai_sub_reg_wr(struct stm32_sai_sub_data *sai,
206*4882a593Smuzhiyun 				unsigned int reg, unsigned int mask,
207*4882a593Smuzhiyun 				unsigned int val)
208*4882a593Smuzhiyun {
209*4882a593Smuzhiyun 	int ret;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	ret = clk_enable(sai->pdata->pclk);
212*4882a593Smuzhiyun 	if (ret < 0)
213*4882a593Smuzhiyun 		return ret;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	ret = regmap_write_bits(sai->regmap, reg, mask, val);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	clk_disable(sai->pdata->pclk);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	return ret;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
stm32_sai_sub_reg_rd(struct stm32_sai_sub_data * sai,unsigned int reg,unsigned int * val)222*4882a593Smuzhiyun static int stm32_sai_sub_reg_rd(struct stm32_sai_sub_data *sai,
223*4882a593Smuzhiyun 				unsigned int reg, unsigned int *val)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	int ret;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	ret = clk_enable(sai->pdata->pclk);
228*4882a593Smuzhiyun 	if (ret < 0)
229*4882a593Smuzhiyun 		return ret;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	ret = regmap_read(sai->regmap, reg, val);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	clk_disable(sai->pdata->pclk);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	return ret;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun static const struct regmap_config stm32_sai_sub_regmap_config_f4 = {
239*4882a593Smuzhiyun 	.reg_bits = 32,
240*4882a593Smuzhiyun 	.reg_stride = 4,
241*4882a593Smuzhiyun 	.val_bits = 32,
242*4882a593Smuzhiyun 	.max_register = STM_SAI_DR_REGX,
243*4882a593Smuzhiyun 	.readable_reg = stm32_sai_sub_readable_reg,
244*4882a593Smuzhiyun 	.volatile_reg = stm32_sai_sub_volatile_reg,
245*4882a593Smuzhiyun 	.writeable_reg = stm32_sai_sub_writeable_reg,
246*4882a593Smuzhiyun 	.fast_io = true,
247*4882a593Smuzhiyun 	.cache_type = REGCACHE_FLAT,
248*4882a593Smuzhiyun };
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun static const struct regmap_config stm32_sai_sub_regmap_config_h7 = {
251*4882a593Smuzhiyun 	.reg_bits = 32,
252*4882a593Smuzhiyun 	.reg_stride = 4,
253*4882a593Smuzhiyun 	.val_bits = 32,
254*4882a593Smuzhiyun 	.max_register = STM_SAI_PDMLY_REGX,
255*4882a593Smuzhiyun 	.readable_reg = stm32_sai_sub_readable_reg,
256*4882a593Smuzhiyun 	.volatile_reg = stm32_sai_sub_volatile_reg,
257*4882a593Smuzhiyun 	.writeable_reg = stm32_sai_sub_writeable_reg,
258*4882a593Smuzhiyun 	.fast_io = true,
259*4882a593Smuzhiyun 	.cache_type = REGCACHE_FLAT,
260*4882a593Smuzhiyun };
261*4882a593Smuzhiyun 
snd_pcm_iec958_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)262*4882a593Smuzhiyun static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol,
263*4882a593Smuzhiyun 			       struct snd_ctl_elem_info *uinfo)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
266*4882a593Smuzhiyun 	uinfo->count = 1;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	return 0;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
snd_pcm_iec958_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * uctl)271*4882a593Smuzhiyun static int snd_pcm_iec958_get(struct snd_kcontrol *kcontrol,
272*4882a593Smuzhiyun 			      struct snd_ctl_elem_value *uctl)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_kcontrol_chip(kcontrol);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	mutex_lock(&sai->ctrl_lock);
277*4882a593Smuzhiyun 	memcpy(uctl->value.iec958.status, sai->iec958.status, 4);
278*4882a593Smuzhiyun 	mutex_unlock(&sai->ctrl_lock);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	return 0;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
snd_pcm_iec958_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * uctl)283*4882a593Smuzhiyun static int snd_pcm_iec958_put(struct snd_kcontrol *kcontrol,
284*4882a593Smuzhiyun 			      struct snd_ctl_elem_value *uctl)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_kcontrol_chip(kcontrol);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	mutex_lock(&sai->ctrl_lock);
289*4882a593Smuzhiyun 	memcpy(sai->iec958.status, uctl->value.iec958.status, 4);
290*4882a593Smuzhiyun 	mutex_unlock(&sai->ctrl_lock);
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	return 0;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun static const struct snd_kcontrol_new iec958_ctls = {
296*4882a593Smuzhiyun 	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
297*4882a593Smuzhiyun 			SNDRV_CTL_ELEM_ACCESS_VOLATILE),
298*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_PCM,
299*4882a593Smuzhiyun 	.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
300*4882a593Smuzhiyun 	.info = snd_pcm_iec958_info,
301*4882a593Smuzhiyun 	.get = snd_pcm_iec958_get,
302*4882a593Smuzhiyun 	.put = snd_pcm_iec958_put,
303*4882a593Smuzhiyun };
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun struct stm32_sai_mclk_data {
306*4882a593Smuzhiyun 	struct clk_hw hw;
307*4882a593Smuzhiyun 	unsigned long freq;
308*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai_data;
309*4882a593Smuzhiyun };
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun #define to_mclk_data(_hw) container_of(_hw, struct stm32_sai_mclk_data, hw)
312*4882a593Smuzhiyun #define STM32_SAI_MAX_CLKS 1
313*4882a593Smuzhiyun 
stm32_sai_get_clk_div(struct stm32_sai_sub_data * sai,unsigned long input_rate,unsigned long output_rate)314*4882a593Smuzhiyun static int stm32_sai_get_clk_div(struct stm32_sai_sub_data *sai,
315*4882a593Smuzhiyun 				 unsigned long input_rate,
316*4882a593Smuzhiyun 				 unsigned long output_rate)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun 	int version = sai->pdata->conf.version;
319*4882a593Smuzhiyun 	int div;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	div = DIV_ROUND_CLOSEST(input_rate, output_rate);
322*4882a593Smuzhiyun 	if (div > SAI_XCR1_MCKDIV_MAX(version)) {
323*4882a593Smuzhiyun 		dev_err(&sai->pdev->dev, "Divider %d out of range\n", div);
324*4882a593Smuzhiyun 		return -EINVAL;
325*4882a593Smuzhiyun 	}
326*4882a593Smuzhiyun 	dev_dbg(&sai->pdev->dev, "SAI divider %d\n", div);
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	if (input_rate % div)
329*4882a593Smuzhiyun 		dev_dbg(&sai->pdev->dev,
330*4882a593Smuzhiyun 			"Rate not accurate. requested (%ld), actual (%ld)\n",
331*4882a593Smuzhiyun 			output_rate, input_rate / div);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	return div;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun 
stm32_sai_set_clk_div(struct stm32_sai_sub_data * sai,unsigned int div)336*4882a593Smuzhiyun static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai,
337*4882a593Smuzhiyun 				 unsigned int div)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun 	int version = sai->pdata->conf.version;
340*4882a593Smuzhiyun 	int ret, cr1, mask;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	if (div > SAI_XCR1_MCKDIV_MAX(version)) {
343*4882a593Smuzhiyun 		dev_err(&sai->pdev->dev, "Divider %d out of range\n", div);
344*4882a593Smuzhiyun 		return -EINVAL;
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version));
348*4882a593Smuzhiyun 	cr1 = SAI_XCR1_MCKDIV_SET(div);
349*4882a593Smuzhiyun 	ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, mask, cr1);
350*4882a593Smuzhiyun 	if (ret < 0)
351*4882a593Smuzhiyun 		dev_err(&sai->pdev->dev, "Failed to update CR1 register\n");
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	return ret;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
stm32_sai_set_parent_clock(struct stm32_sai_sub_data * sai,unsigned int rate)356*4882a593Smuzhiyun static int stm32_sai_set_parent_clock(struct stm32_sai_sub_data *sai,
357*4882a593Smuzhiyun 				      unsigned int rate)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	struct platform_device *pdev = sai->pdev;
360*4882a593Smuzhiyun 	struct clk *parent_clk = sai->pdata->clk_x8k;
361*4882a593Smuzhiyun 	int ret;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if (!(rate % SAI_RATE_11K))
364*4882a593Smuzhiyun 		parent_clk = sai->pdata->clk_x11k;
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	ret = clk_set_parent(sai->sai_ck, parent_clk);
367*4882a593Smuzhiyun 	if (ret)
368*4882a593Smuzhiyun 		dev_err(&pdev->dev, " Error %d setting sai_ck parent clock. %s",
369*4882a593Smuzhiyun 			ret, ret == -EBUSY ?
370*4882a593Smuzhiyun 			"Active stream rates conflict\n" : "\n");
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	return ret;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
stm32_sai_mclk_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)375*4882a593Smuzhiyun static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate,
376*4882a593Smuzhiyun 				      unsigned long *prate)
377*4882a593Smuzhiyun {
378*4882a593Smuzhiyun 	struct stm32_sai_mclk_data *mclk = to_mclk_data(hw);
379*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = mclk->sai_data;
380*4882a593Smuzhiyun 	int div;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	div = stm32_sai_get_clk_div(sai, *prate, rate);
383*4882a593Smuzhiyun 	if (div < 0)
384*4882a593Smuzhiyun 		return div;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	mclk->freq = *prate / div;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	return mclk->freq;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
stm32_sai_mclk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)391*4882a593Smuzhiyun static unsigned long stm32_sai_mclk_recalc_rate(struct clk_hw *hw,
392*4882a593Smuzhiyun 						unsigned long parent_rate)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	struct stm32_sai_mclk_data *mclk = to_mclk_data(hw);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	return mclk->freq;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
stm32_sai_mclk_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)399*4882a593Smuzhiyun static int stm32_sai_mclk_set_rate(struct clk_hw *hw, unsigned long rate,
400*4882a593Smuzhiyun 				   unsigned long parent_rate)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	struct stm32_sai_mclk_data *mclk = to_mclk_data(hw);
403*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = mclk->sai_data;
404*4882a593Smuzhiyun 	int div, ret;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	div = stm32_sai_get_clk_div(sai, parent_rate, rate);
407*4882a593Smuzhiyun 	if (div < 0)
408*4882a593Smuzhiyun 		return div;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	ret = stm32_sai_set_clk_div(sai, div);
411*4882a593Smuzhiyun 	if (ret)
412*4882a593Smuzhiyun 		return ret;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	mclk->freq = rate;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	return 0;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
stm32_sai_mclk_enable(struct clk_hw * hw)419*4882a593Smuzhiyun static int stm32_sai_mclk_enable(struct clk_hw *hw)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	struct stm32_sai_mclk_data *mclk = to_mclk_data(hw);
422*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = mclk->sai_data;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	dev_dbg(&sai->pdev->dev, "Enable master clock\n");
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
427*4882a593Smuzhiyun 				    SAI_XCR1_MCKEN, SAI_XCR1_MCKEN);
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
stm32_sai_mclk_disable(struct clk_hw * hw)430*4882a593Smuzhiyun static void stm32_sai_mclk_disable(struct clk_hw *hw)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun 	struct stm32_sai_mclk_data *mclk = to_mclk_data(hw);
433*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = mclk->sai_data;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	dev_dbg(&sai->pdev->dev, "Disable master clock\n");
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, SAI_XCR1_MCKEN, 0);
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun static const struct clk_ops mclk_ops = {
441*4882a593Smuzhiyun 	.enable = stm32_sai_mclk_enable,
442*4882a593Smuzhiyun 	.disable = stm32_sai_mclk_disable,
443*4882a593Smuzhiyun 	.recalc_rate = stm32_sai_mclk_recalc_rate,
444*4882a593Smuzhiyun 	.round_rate = stm32_sai_mclk_round_rate,
445*4882a593Smuzhiyun 	.set_rate = stm32_sai_mclk_set_rate,
446*4882a593Smuzhiyun };
447*4882a593Smuzhiyun 
stm32_sai_add_mclk_provider(struct stm32_sai_sub_data * sai)448*4882a593Smuzhiyun static int stm32_sai_add_mclk_provider(struct stm32_sai_sub_data *sai)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct clk_hw *hw;
451*4882a593Smuzhiyun 	struct stm32_sai_mclk_data *mclk;
452*4882a593Smuzhiyun 	struct device *dev = &sai->pdev->dev;
453*4882a593Smuzhiyun 	const char *pname = __clk_get_name(sai->sai_ck);
454*4882a593Smuzhiyun 	char *mclk_name, *p, *s = (char *)pname;
455*4882a593Smuzhiyun 	int ret, i = 0;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	mclk = devm_kzalloc(dev, sizeof(*mclk), GFP_KERNEL);
458*4882a593Smuzhiyun 	if (!mclk)
459*4882a593Smuzhiyun 		return -ENOMEM;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	mclk_name = devm_kcalloc(dev, sizeof(char),
462*4882a593Smuzhiyun 				 SAI_MCLK_NAME_LEN, GFP_KERNEL);
463*4882a593Smuzhiyun 	if (!mclk_name)
464*4882a593Smuzhiyun 		return -ENOMEM;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	/*
467*4882a593Smuzhiyun 	 * Forge mclk clock name from parent clock name and suffix.
468*4882a593Smuzhiyun 	 * String after "_" char is stripped in parent name.
469*4882a593Smuzhiyun 	 */
470*4882a593Smuzhiyun 	p = mclk_name;
471*4882a593Smuzhiyun 	while (*s && *s != '_' && (i < (SAI_MCLK_NAME_LEN - 7))) {
472*4882a593Smuzhiyun 		*p++ = *s++;
473*4882a593Smuzhiyun 		i++;
474*4882a593Smuzhiyun 	}
475*4882a593Smuzhiyun 	STM_SAI_IS_SUB_A(sai) ? strcat(p, "a_mclk") : strcat(p, "b_mclk");
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	mclk->hw.init = CLK_HW_INIT(mclk_name, pname, &mclk_ops, 0);
478*4882a593Smuzhiyun 	mclk->sai_data = sai;
479*4882a593Smuzhiyun 	hw = &mclk->hw;
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	dev_dbg(dev, "Register master clock %s\n", mclk_name);
482*4882a593Smuzhiyun 	ret = devm_clk_hw_register(&sai->pdev->dev, hw);
483*4882a593Smuzhiyun 	if (ret) {
484*4882a593Smuzhiyun 		dev_err(dev, "mclk register returned %d\n", ret);
485*4882a593Smuzhiyun 		return ret;
486*4882a593Smuzhiyun 	}
487*4882a593Smuzhiyun 	sai->sai_mclk = hw->clk;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	/* register mclk provider */
490*4882a593Smuzhiyun 	return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun 
stm32_sai_isr(int irq,void * devid)493*4882a593Smuzhiyun static irqreturn_t stm32_sai_isr(int irq, void *devid)
494*4882a593Smuzhiyun {
495*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
496*4882a593Smuzhiyun 	struct platform_device *pdev = sai->pdev;
497*4882a593Smuzhiyun 	unsigned int sr, imr, flags;
498*4882a593Smuzhiyun 	snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	stm32_sai_sub_reg_rd(sai, STM_SAI_IMR_REGX, &imr);
501*4882a593Smuzhiyun 	stm32_sai_sub_reg_rd(sai, STM_SAI_SR_REGX, &sr);
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	flags = sr & imr;
504*4882a593Smuzhiyun 	if (!flags)
505*4882a593Smuzhiyun 		return IRQ_NONE;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
508*4882a593Smuzhiyun 			     SAI_XCLRFR_MASK);
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	if (!sai->substream) {
511*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr);
512*4882a593Smuzhiyun 		return IRQ_NONE;
513*4882a593Smuzhiyun 	}
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	if (flags & SAI_XIMR_OVRUDRIE) {
516*4882a593Smuzhiyun 		dev_err(&pdev->dev, "IRQ %s\n",
517*4882a593Smuzhiyun 			STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
518*4882a593Smuzhiyun 		status = SNDRV_PCM_STATE_XRUN;
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	if (flags & SAI_XIMR_MUTEDETIE)
522*4882a593Smuzhiyun 		dev_dbg(&pdev->dev, "IRQ mute detected\n");
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 	if (flags & SAI_XIMR_WCKCFGIE) {
525*4882a593Smuzhiyun 		dev_err(&pdev->dev, "IRQ wrong clock configuration\n");
526*4882a593Smuzhiyun 		status = SNDRV_PCM_STATE_DISCONNECTED;
527*4882a593Smuzhiyun 	}
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	if (flags & SAI_XIMR_CNRDYIE)
530*4882a593Smuzhiyun 		dev_err(&pdev->dev, "IRQ Codec not ready\n");
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	if (flags & SAI_XIMR_AFSDETIE) {
533*4882a593Smuzhiyun 		dev_err(&pdev->dev, "IRQ Anticipated frame synchro\n");
534*4882a593Smuzhiyun 		status = SNDRV_PCM_STATE_XRUN;
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	if (flags & SAI_XIMR_LFSDETIE) {
538*4882a593Smuzhiyun 		dev_err(&pdev->dev, "IRQ Late frame synchro\n");
539*4882a593Smuzhiyun 		status = SNDRV_PCM_STATE_XRUN;
540*4882a593Smuzhiyun 	}
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	spin_lock(&sai->irq_lock);
543*4882a593Smuzhiyun 	if (status != SNDRV_PCM_STATE_RUNNING && sai->substream)
544*4882a593Smuzhiyun 		snd_pcm_stop_xrun(sai->substream);
545*4882a593Smuzhiyun 	spin_unlock(&sai->irq_lock);
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	return IRQ_HANDLED;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
stm32_sai_set_sysclk(struct snd_soc_dai * cpu_dai,int clk_id,unsigned int freq,int dir)550*4882a593Smuzhiyun static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai,
551*4882a593Smuzhiyun 				int clk_id, unsigned int freq, int dir)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
554*4882a593Smuzhiyun 	int ret;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) {
557*4882a593Smuzhiyun 		ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
558*4882a593Smuzhiyun 					   SAI_XCR1_NODIV,
559*4882a593Smuzhiyun 					 freq ? 0 : SAI_XCR1_NODIV);
560*4882a593Smuzhiyun 		if (ret < 0)
561*4882a593Smuzhiyun 			return ret;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 		/* Assume shutdown if requested frequency is 0Hz */
564*4882a593Smuzhiyun 		if (!freq) {
565*4882a593Smuzhiyun 			/* Release mclk rate only if rate was actually set */
566*4882a593Smuzhiyun 			if (sai->mclk_rate) {
567*4882a593Smuzhiyun 				clk_rate_exclusive_put(sai->sai_mclk);
568*4882a593Smuzhiyun 				sai->mclk_rate = 0;
569*4882a593Smuzhiyun 			}
570*4882a593Smuzhiyun 			return 0;
571*4882a593Smuzhiyun 		}
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 		/* If master clock is used, set parent clock now */
574*4882a593Smuzhiyun 		ret = stm32_sai_set_parent_clock(sai, freq);
575*4882a593Smuzhiyun 		if (ret)
576*4882a593Smuzhiyun 			return ret;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 		ret = clk_set_rate_exclusive(sai->sai_mclk, freq);
579*4882a593Smuzhiyun 		if (ret) {
580*4882a593Smuzhiyun 			dev_err(cpu_dai->dev,
581*4882a593Smuzhiyun 				ret == -EBUSY ?
582*4882a593Smuzhiyun 				"Active streams have incompatible rates" :
583*4882a593Smuzhiyun 				"Could not set mclk rate\n");
584*4882a593Smuzhiyun 			return ret;
585*4882a593Smuzhiyun 		}
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 		dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq);
588*4882a593Smuzhiyun 		sai->mclk_rate = freq;
589*4882a593Smuzhiyun 	}
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	return 0;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
stm32_sai_set_dai_tdm_slot(struct snd_soc_dai * cpu_dai,u32 tx_mask,u32 rx_mask,int slots,int slot_width)594*4882a593Smuzhiyun static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
595*4882a593Smuzhiyun 				      u32 rx_mask, int slots, int slot_width)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
598*4882a593Smuzhiyun 	int slotr, slotr_mask, slot_size;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
601*4882a593Smuzhiyun 		dev_warn(cpu_dai->dev, "Slot setting relevant only for TDM\n");
602*4882a593Smuzhiyun 		return 0;
603*4882a593Smuzhiyun 	}
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n",
606*4882a593Smuzhiyun 		tx_mask, rx_mask, slots, slot_width);
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	switch (slot_width) {
609*4882a593Smuzhiyun 	case 16:
610*4882a593Smuzhiyun 		slot_size = SAI_SLOT_SIZE_16;
611*4882a593Smuzhiyun 		break;
612*4882a593Smuzhiyun 	case 32:
613*4882a593Smuzhiyun 		slot_size = SAI_SLOT_SIZE_32;
614*4882a593Smuzhiyun 		break;
615*4882a593Smuzhiyun 	default:
616*4882a593Smuzhiyun 		slot_size = SAI_SLOT_SIZE_AUTO;
617*4882a593Smuzhiyun 		break;
618*4882a593Smuzhiyun 	}
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	slotr = SAI_XSLOTR_SLOTSZ_SET(slot_size) |
621*4882a593Smuzhiyun 		SAI_XSLOTR_NBSLOT_SET(slots - 1);
622*4882a593Smuzhiyun 	slotr_mask = SAI_XSLOTR_SLOTSZ_MASK | SAI_XSLOTR_NBSLOT_MASK;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	/* tx/rx mask set in machine init, if slot number defined in DT */
625*4882a593Smuzhiyun 	if (STM_SAI_IS_PLAYBACK(sai)) {
626*4882a593Smuzhiyun 		sai->slot_mask = tx_mask;
627*4882a593Smuzhiyun 		slotr |= SAI_XSLOTR_SLOTEN_SET(tx_mask);
628*4882a593Smuzhiyun 	}
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	if (STM_SAI_IS_CAPTURE(sai)) {
631*4882a593Smuzhiyun 		sai->slot_mask = rx_mask;
632*4882a593Smuzhiyun 		slotr |= SAI_XSLOTR_SLOTEN_SET(rx_mask);
633*4882a593Smuzhiyun 	}
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	slotr_mask |= SAI_XSLOTR_SLOTEN_MASK;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX, slotr_mask, slotr);
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	sai->slot_width = slot_width;
640*4882a593Smuzhiyun 	sai->slots = slots;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	return 0;
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun 
stm32_sai_set_dai_fmt(struct snd_soc_dai * cpu_dai,unsigned int fmt)645*4882a593Smuzhiyun static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
648*4882a593Smuzhiyun 	int cr1, frcr = 0;
649*4882a593Smuzhiyun 	int cr1_mask, frcr_mask = 0;
650*4882a593Smuzhiyun 	int ret;
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun 	dev_dbg(cpu_dai->dev, "fmt %x\n", fmt);
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	/* Do not generate master by default */
655*4882a593Smuzhiyun 	cr1 = SAI_XCR1_NODIV;
656*4882a593Smuzhiyun 	cr1_mask = SAI_XCR1_NODIV;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	cr1_mask |= SAI_XCR1_PRTCFG_MASK;
659*4882a593Smuzhiyun 	if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
660*4882a593Smuzhiyun 		cr1 |= SAI_XCR1_PRTCFG_SET(SAI_SPDIF_PROTOCOL);
661*4882a593Smuzhiyun 		goto conf_update;
662*4882a593Smuzhiyun 	}
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	cr1 |= SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
667*4882a593Smuzhiyun 	/* SCK active high for all protocols */
668*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
669*4882a593Smuzhiyun 		cr1 |= SAI_XCR1_CKSTR;
670*4882a593Smuzhiyun 		frcr |= SAI_XFRCR_FSOFF | SAI_XFRCR_FSDEF;
671*4882a593Smuzhiyun 		break;
672*4882a593Smuzhiyun 	/* Left justified */
673*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_MSB:
674*4882a593Smuzhiyun 		frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSDEF;
675*4882a593Smuzhiyun 		break;
676*4882a593Smuzhiyun 	/* Right justified */
677*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_LSB:
678*4882a593Smuzhiyun 		frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSDEF;
679*4882a593Smuzhiyun 		break;
680*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
681*4882a593Smuzhiyun 		frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF;
682*4882a593Smuzhiyun 		break;
683*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
684*4882a593Smuzhiyun 		frcr |= SAI_XFRCR_FSPOL;
685*4882a593Smuzhiyun 		break;
686*4882a593Smuzhiyun 	default:
687*4882a593Smuzhiyun 		dev_err(cpu_dai->dev, "Unsupported protocol %#x\n",
688*4882a593Smuzhiyun 			fmt & SND_SOC_DAIFMT_FORMAT_MASK);
689*4882a593Smuzhiyun 		return -EINVAL;
690*4882a593Smuzhiyun 	}
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	cr1_mask |= SAI_XCR1_CKSTR;
693*4882a593Smuzhiyun 	frcr_mask |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF |
694*4882a593Smuzhiyun 		     SAI_XFRCR_FSDEF;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	/* DAI clock strobing. Invert setting previously set */
697*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
698*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
699*4882a593Smuzhiyun 		break;
700*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_NF:
701*4882a593Smuzhiyun 		cr1 ^= SAI_XCR1_CKSTR;
702*4882a593Smuzhiyun 		break;
703*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
704*4882a593Smuzhiyun 		frcr ^= SAI_XFRCR_FSPOL;
705*4882a593Smuzhiyun 		break;
706*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_IF:
707*4882a593Smuzhiyun 		/* Invert fs & sck */
708*4882a593Smuzhiyun 		cr1 ^= SAI_XCR1_CKSTR;
709*4882a593Smuzhiyun 		frcr ^= SAI_XFRCR_FSPOL;
710*4882a593Smuzhiyun 		break;
711*4882a593Smuzhiyun 	default:
712*4882a593Smuzhiyun 		dev_err(cpu_dai->dev, "Unsupported strobing %#x\n",
713*4882a593Smuzhiyun 			fmt & SND_SOC_DAIFMT_INV_MASK);
714*4882a593Smuzhiyun 		return -EINVAL;
715*4882a593Smuzhiyun 	}
716*4882a593Smuzhiyun 	cr1_mask |= SAI_XCR1_CKSTR;
717*4882a593Smuzhiyun 	frcr_mask |= SAI_XFRCR_FSPOL;
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr);
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	/* DAI clock master masks */
722*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
723*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
724*4882a593Smuzhiyun 		/* codec is master */
725*4882a593Smuzhiyun 		cr1 |= SAI_XCR1_SLAVE;
726*4882a593Smuzhiyun 		sai->master = false;
727*4882a593Smuzhiyun 		break;
728*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
729*4882a593Smuzhiyun 		sai->master = true;
730*4882a593Smuzhiyun 		break;
731*4882a593Smuzhiyun 	default:
732*4882a593Smuzhiyun 		dev_err(cpu_dai->dev, "Unsupported mode %#x\n",
733*4882a593Smuzhiyun 			fmt & SND_SOC_DAIFMT_MASTER_MASK);
734*4882a593Smuzhiyun 		return -EINVAL;
735*4882a593Smuzhiyun 	}
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	/* Set slave mode if sub-block is synchronized with another SAI */
738*4882a593Smuzhiyun 	if (sai->sync) {
739*4882a593Smuzhiyun 		dev_dbg(cpu_dai->dev, "Synchronized SAI configured as slave\n");
740*4882a593Smuzhiyun 		cr1 |= SAI_XCR1_SLAVE;
741*4882a593Smuzhiyun 		sai->master = false;
742*4882a593Smuzhiyun 	}
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	cr1_mask |= SAI_XCR1_SLAVE;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun conf_update:
747*4882a593Smuzhiyun 	ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
748*4882a593Smuzhiyun 	if (ret < 0) {
749*4882a593Smuzhiyun 		dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
750*4882a593Smuzhiyun 		return ret;
751*4882a593Smuzhiyun 	}
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	sai->fmt = fmt;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	return 0;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun 
stm32_sai_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)758*4882a593Smuzhiyun static int stm32_sai_startup(struct snd_pcm_substream *substream,
759*4882a593Smuzhiyun 			     struct snd_soc_dai *cpu_dai)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
762*4882a593Smuzhiyun 	int imr, cr2, ret;
763*4882a593Smuzhiyun 	unsigned long flags;
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	spin_lock_irqsave(&sai->irq_lock, flags);
766*4882a593Smuzhiyun 	sai->substream = substream;
767*4882a593Smuzhiyun 	spin_unlock_irqrestore(&sai->irq_lock, flags);
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
770*4882a593Smuzhiyun 		snd_pcm_hw_constraint_mask64(substream->runtime,
771*4882a593Smuzhiyun 					     SNDRV_PCM_HW_PARAM_FORMAT,
772*4882a593Smuzhiyun 					     SNDRV_PCM_FMTBIT_S32_LE);
773*4882a593Smuzhiyun 		snd_pcm_hw_constraint_single(substream->runtime,
774*4882a593Smuzhiyun 					     SNDRV_PCM_HW_PARAM_CHANNELS, 2);
775*4882a593Smuzhiyun 	}
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	ret = clk_prepare_enable(sai->sai_ck);
778*4882a593Smuzhiyun 	if (ret < 0) {
779*4882a593Smuzhiyun 		dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret);
780*4882a593Smuzhiyun 		return ret;
781*4882a593Smuzhiyun 	}
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 	/* Enable ITs */
784*4882a593Smuzhiyun 	stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX,
785*4882a593Smuzhiyun 			     SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	imr = SAI_XIMR_OVRUDRIE;
788*4882a593Smuzhiyun 	if (STM_SAI_IS_CAPTURE(sai)) {
789*4882a593Smuzhiyun 		stm32_sai_sub_reg_rd(sai, STM_SAI_CR2_REGX, &cr2);
790*4882a593Smuzhiyun 		if (cr2 & SAI_XCR2_MUTECNT_MASK)
791*4882a593Smuzhiyun 			imr |= SAI_XIMR_MUTEDETIE;
792*4882a593Smuzhiyun 	}
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	if (sai->master)
795*4882a593Smuzhiyun 		imr |= SAI_XIMR_WCKCFGIE;
796*4882a593Smuzhiyun 	else
797*4882a593Smuzhiyun 		imr |= SAI_XIMR_AFSDETIE | SAI_XIMR_LFSDETIE;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX,
800*4882a593Smuzhiyun 			     SAI_XIMR_MASK, imr);
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	return 0;
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun 
stm32_sai_set_config(struct snd_soc_dai * cpu_dai,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)805*4882a593Smuzhiyun static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
806*4882a593Smuzhiyun 				struct snd_pcm_substream *substream,
807*4882a593Smuzhiyun 				struct snd_pcm_hw_params *params)
808*4882a593Smuzhiyun {
809*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
810*4882a593Smuzhiyun 	int cr1, cr1_mask, ret;
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	/*
813*4882a593Smuzhiyun 	 * DMA bursts increment is set to 4 words.
814*4882a593Smuzhiyun 	 * SAI fifo threshold is set to half fifo, to keep enough space
815*4882a593Smuzhiyun 	 * for DMA incoming bursts.
816*4882a593Smuzhiyun 	 */
817*4882a593Smuzhiyun 	stm32_sai_sub_reg_wr(sai, STM_SAI_CR2_REGX,
818*4882a593Smuzhiyun 			     SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
819*4882a593Smuzhiyun 			     SAI_XCR2_FFLUSH |
820*4882a593Smuzhiyun 			     SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF));
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 	/* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/
823*4882a593Smuzhiyun 	if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
824*4882a593Smuzhiyun 		sai->spdif_frm_cnt = 0;
825*4882a593Smuzhiyun 		return 0;
826*4882a593Smuzhiyun 	}
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	/* Mode, data format and channel config */
829*4882a593Smuzhiyun 	cr1_mask = SAI_XCR1_DS_MASK;
830*4882a593Smuzhiyun 	switch (params_format(params)) {
831*4882a593Smuzhiyun 	case SNDRV_PCM_FORMAT_S8:
832*4882a593Smuzhiyun 		cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_8);
833*4882a593Smuzhiyun 		break;
834*4882a593Smuzhiyun 	case SNDRV_PCM_FORMAT_S16_LE:
835*4882a593Smuzhiyun 		cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_16);
836*4882a593Smuzhiyun 		break;
837*4882a593Smuzhiyun 	case SNDRV_PCM_FORMAT_S32_LE:
838*4882a593Smuzhiyun 		cr1 = SAI_XCR1_DS_SET(SAI_DATASIZE_32);
839*4882a593Smuzhiyun 		break;
840*4882a593Smuzhiyun 	default:
841*4882a593Smuzhiyun 		dev_err(cpu_dai->dev, "Data format not supported\n");
842*4882a593Smuzhiyun 		return -EINVAL;
843*4882a593Smuzhiyun 	}
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	cr1_mask |= SAI_XCR1_MONO;
846*4882a593Smuzhiyun 	if ((sai->slots == 2) && (params_channels(params) == 1))
847*4882a593Smuzhiyun 		cr1 |= SAI_XCR1_MONO;
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
850*4882a593Smuzhiyun 	if (ret < 0) {
851*4882a593Smuzhiyun 		dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
852*4882a593Smuzhiyun 		return ret;
853*4882a593Smuzhiyun 	}
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	return 0;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
stm32_sai_set_slots(struct snd_soc_dai * cpu_dai)858*4882a593Smuzhiyun static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai)
859*4882a593Smuzhiyun {
860*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
861*4882a593Smuzhiyun 	int slotr, slot_sz;
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 	stm32_sai_sub_reg_rd(sai, STM_SAI_SLOTR_REGX, &slotr);
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	/*
866*4882a593Smuzhiyun 	 * If SLOTSZ is set to auto in SLOTR, align slot width on data size
867*4882a593Smuzhiyun 	 * By default slot width = data size, if not forced from DT
868*4882a593Smuzhiyun 	 */
869*4882a593Smuzhiyun 	slot_sz = slotr & SAI_XSLOTR_SLOTSZ_MASK;
870*4882a593Smuzhiyun 	if (slot_sz == SAI_XSLOTR_SLOTSZ_SET(SAI_SLOT_SIZE_AUTO))
871*4882a593Smuzhiyun 		sai->slot_width = sai->data_size;
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	if (sai->slot_width < sai->data_size) {
874*4882a593Smuzhiyun 		dev_err(cpu_dai->dev,
875*4882a593Smuzhiyun 			"Data size %d larger than slot width\n",
876*4882a593Smuzhiyun 			sai->data_size);
877*4882a593Smuzhiyun 		return -EINVAL;
878*4882a593Smuzhiyun 	}
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	/* Slot number is set to 2, if not specified in DT */
881*4882a593Smuzhiyun 	if (!sai->slots)
882*4882a593Smuzhiyun 		sai->slots = 2;
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun 	/* The number of slots in the audio frame is equal to NBSLOT[3:0] + 1*/
885*4882a593Smuzhiyun 	stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX,
886*4882a593Smuzhiyun 			     SAI_XSLOTR_NBSLOT_MASK,
887*4882a593Smuzhiyun 			     SAI_XSLOTR_NBSLOT_SET((sai->slots - 1)));
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun 	/* Set default slots mask if not already set from DT */
890*4882a593Smuzhiyun 	if (!(slotr & SAI_XSLOTR_SLOTEN_MASK)) {
891*4882a593Smuzhiyun 		sai->slot_mask = (1 << sai->slots) - 1;
892*4882a593Smuzhiyun 		stm32_sai_sub_reg_up(sai,
893*4882a593Smuzhiyun 				     STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK,
894*4882a593Smuzhiyun 				     SAI_XSLOTR_SLOTEN_SET(sai->slot_mask));
895*4882a593Smuzhiyun 	}
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n",
898*4882a593Smuzhiyun 		sai->slots, sai->slot_width);
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 	return 0;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun 
stm32_sai_set_frame(struct snd_soc_dai * cpu_dai)903*4882a593Smuzhiyun static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai)
904*4882a593Smuzhiyun {
905*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
906*4882a593Smuzhiyun 	int fs_active, offset, format;
907*4882a593Smuzhiyun 	int frcr, frcr_mask;
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	format = sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
910*4882a593Smuzhiyun 	sai->fs_length = sai->slot_width * sai->slots;
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	fs_active = sai->fs_length / 2;
913*4882a593Smuzhiyun 	if ((format == SND_SOC_DAIFMT_DSP_A) ||
914*4882a593Smuzhiyun 	    (format == SND_SOC_DAIFMT_DSP_B))
915*4882a593Smuzhiyun 		fs_active = 1;
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	frcr = SAI_XFRCR_FRL_SET((sai->fs_length - 1));
918*4882a593Smuzhiyun 	frcr |= SAI_XFRCR_FSALL_SET((fs_active - 1));
919*4882a593Smuzhiyun 	frcr_mask = SAI_XFRCR_FRL_MASK | SAI_XFRCR_FSALL_MASK;
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 	dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n",
922*4882a593Smuzhiyun 		sai->fs_length, fs_active);
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr);
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	if ((sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LSB) {
927*4882a593Smuzhiyun 		offset = sai->slot_width - sai->data_size;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 		stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX,
930*4882a593Smuzhiyun 				     SAI_XSLOTR_FBOFF_MASK,
931*4882a593Smuzhiyun 				     SAI_XSLOTR_FBOFF_SET(offset));
932*4882a593Smuzhiyun 	}
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun 
stm32_sai_init_iec958_status(struct stm32_sai_sub_data * sai)935*4882a593Smuzhiyun static void stm32_sai_init_iec958_status(struct stm32_sai_sub_data *sai)
936*4882a593Smuzhiyun {
937*4882a593Smuzhiyun 	unsigned char *cs = sai->iec958.status;
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
940*4882a593Smuzhiyun 	cs[1] = IEC958_AES1_CON_GENERAL;
941*4882a593Smuzhiyun 	cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
942*4882a593Smuzhiyun 	cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID;
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun 
stm32_sai_set_iec958_status(struct stm32_sai_sub_data * sai,struct snd_pcm_runtime * runtime)945*4882a593Smuzhiyun static void stm32_sai_set_iec958_status(struct stm32_sai_sub_data *sai,
946*4882a593Smuzhiyun 					struct snd_pcm_runtime *runtime)
947*4882a593Smuzhiyun {
948*4882a593Smuzhiyun 	if (!runtime)
949*4882a593Smuzhiyun 		return;
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	/* Force the sample rate according to runtime rate */
952*4882a593Smuzhiyun 	mutex_lock(&sai->ctrl_lock);
953*4882a593Smuzhiyun 	switch (runtime->rate) {
954*4882a593Smuzhiyun 	case 22050:
955*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_22050;
956*4882a593Smuzhiyun 		break;
957*4882a593Smuzhiyun 	case 44100:
958*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_44100;
959*4882a593Smuzhiyun 		break;
960*4882a593Smuzhiyun 	case 88200:
961*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_88200;
962*4882a593Smuzhiyun 		break;
963*4882a593Smuzhiyun 	case 176400:
964*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_176400;
965*4882a593Smuzhiyun 		break;
966*4882a593Smuzhiyun 	case 24000:
967*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_24000;
968*4882a593Smuzhiyun 		break;
969*4882a593Smuzhiyun 	case 48000:
970*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_48000;
971*4882a593Smuzhiyun 		break;
972*4882a593Smuzhiyun 	case 96000:
973*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_96000;
974*4882a593Smuzhiyun 		break;
975*4882a593Smuzhiyun 	case 192000:
976*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_192000;
977*4882a593Smuzhiyun 		break;
978*4882a593Smuzhiyun 	case 32000:
979*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_32000;
980*4882a593Smuzhiyun 		break;
981*4882a593Smuzhiyun 	default:
982*4882a593Smuzhiyun 		sai->iec958.status[3] = IEC958_AES3_CON_FS_NOTID;
983*4882a593Smuzhiyun 		break;
984*4882a593Smuzhiyun 	}
985*4882a593Smuzhiyun 	mutex_unlock(&sai->ctrl_lock);
986*4882a593Smuzhiyun }
987*4882a593Smuzhiyun 
stm32_sai_configure_clock(struct snd_soc_dai * cpu_dai,struct snd_pcm_hw_params * params)988*4882a593Smuzhiyun static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
989*4882a593Smuzhiyun 				     struct snd_pcm_hw_params *params)
990*4882a593Smuzhiyun {
991*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
992*4882a593Smuzhiyun 	int div = 0, cr1 = 0;
993*4882a593Smuzhiyun 	int sai_clk_rate, mclk_ratio, den;
994*4882a593Smuzhiyun 	unsigned int rate = params_rate(params);
995*4882a593Smuzhiyun 	int ret;
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 	if (!sai->sai_mclk) {
998*4882a593Smuzhiyun 		ret = stm32_sai_set_parent_clock(sai, rate);
999*4882a593Smuzhiyun 		if (ret)
1000*4882a593Smuzhiyun 			return ret;
1001*4882a593Smuzhiyun 	}
1002*4882a593Smuzhiyun 	sai_clk_rate = clk_get_rate(sai->sai_ck);
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun 	if (STM_SAI_IS_F4(sai->pdata)) {
1005*4882a593Smuzhiyun 		/* mclk on (NODIV=0)
1006*4882a593Smuzhiyun 		 *   mclk_rate = 256 * fs
1007*4882a593Smuzhiyun 		 *   MCKDIV = 0 if sai_ck < 3/2 * mclk_rate
1008*4882a593Smuzhiyun 		 *   MCKDIV = sai_ck / (2 * mclk_rate) otherwise
1009*4882a593Smuzhiyun 		 * mclk off (NODIV=1)
1010*4882a593Smuzhiyun 		 *   MCKDIV ignored. sck = sai_ck
1011*4882a593Smuzhiyun 		 */
1012*4882a593Smuzhiyun 		if (!sai->mclk_rate)
1013*4882a593Smuzhiyun 			return 0;
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 		if (2 * sai_clk_rate >= 3 * sai->mclk_rate) {
1016*4882a593Smuzhiyun 			div = stm32_sai_get_clk_div(sai, sai_clk_rate,
1017*4882a593Smuzhiyun 						    2 * sai->mclk_rate);
1018*4882a593Smuzhiyun 			if (div < 0)
1019*4882a593Smuzhiyun 				return div;
1020*4882a593Smuzhiyun 		}
1021*4882a593Smuzhiyun 	} else {
1022*4882a593Smuzhiyun 		/*
1023*4882a593Smuzhiyun 		 * TDM mode :
1024*4882a593Smuzhiyun 		 *   mclk on
1025*4882a593Smuzhiyun 		 *      MCKDIV = sai_ck / (ws x 256)	(NOMCK=0. OSR=0)
1026*4882a593Smuzhiyun 		 *      MCKDIV = sai_ck / (ws x 512)	(NOMCK=0. OSR=1)
1027*4882a593Smuzhiyun 		 *   mclk off
1028*4882a593Smuzhiyun 		 *      MCKDIV = sai_ck / (frl x ws)	(NOMCK=1)
1029*4882a593Smuzhiyun 		 * Note: NOMCK/NODIV correspond to same bit.
1030*4882a593Smuzhiyun 		 */
1031*4882a593Smuzhiyun 		if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
1032*4882a593Smuzhiyun 			div = stm32_sai_get_clk_div(sai, sai_clk_rate,
1033*4882a593Smuzhiyun 						    rate * 128);
1034*4882a593Smuzhiyun 			if (div < 0)
1035*4882a593Smuzhiyun 				return div;
1036*4882a593Smuzhiyun 		} else {
1037*4882a593Smuzhiyun 			if (sai->mclk_rate) {
1038*4882a593Smuzhiyun 				mclk_ratio = sai->mclk_rate / rate;
1039*4882a593Smuzhiyun 				if (mclk_ratio == 512) {
1040*4882a593Smuzhiyun 					cr1 = SAI_XCR1_OSR;
1041*4882a593Smuzhiyun 				} else if (mclk_ratio != 256) {
1042*4882a593Smuzhiyun 					dev_err(cpu_dai->dev,
1043*4882a593Smuzhiyun 						"Wrong mclk ratio %d\n",
1044*4882a593Smuzhiyun 						mclk_ratio);
1045*4882a593Smuzhiyun 					return -EINVAL;
1046*4882a593Smuzhiyun 				}
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 				stm32_sai_sub_reg_up(sai,
1049*4882a593Smuzhiyun 						     STM_SAI_CR1_REGX,
1050*4882a593Smuzhiyun 						     SAI_XCR1_OSR, cr1);
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 				div = stm32_sai_get_clk_div(sai, sai_clk_rate,
1053*4882a593Smuzhiyun 							    sai->mclk_rate);
1054*4882a593Smuzhiyun 				if (div < 0)
1055*4882a593Smuzhiyun 					return div;
1056*4882a593Smuzhiyun 			} else {
1057*4882a593Smuzhiyun 				/* mclk-fs not set, master clock not active */
1058*4882a593Smuzhiyun 				den = sai->fs_length * params_rate(params);
1059*4882a593Smuzhiyun 				div = stm32_sai_get_clk_div(sai, sai_clk_rate,
1060*4882a593Smuzhiyun 							    den);
1061*4882a593Smuzhiyun 				if (div < 0)
1062*4882a593Smuzhiyun 					return div;
1063*4882a593Smuzhiyun 			}
1064*4882a593Smuzhiyun 		}
1065*4882a593Smuzhiyun 	}
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun 	return stm32_sai_set_clk_div(sai, div);
1068*4882a593Smuzhiyun }
1069*4882a593Smuzhiyun 
stm32_sai_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * cpu_dai)1070*4882a593Smuzhiyun static int stm32_sai_hw_params(struct snd_pcm_substream *substream,
1071*4882a593Smuzhiyun 			       struct snd_pcm_hw_params *params,
1072*4882a593Smuzhiyun 			       struct snd_soc_dai *cpu_dai)
1073*4882a593Smuzhiyun {
1074*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
1075*4882a593Smuzhiyun 	int ret;
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	sai->data_size = params_width(params);
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
1080*4882a593Smuzhiyun 		/* Rate not already set in runtime structure */
1081*4882a593Smuzhiyun 		substream->runtime->rate = params_rate(params);
1082*4882a593Smuzhiyun 		stm32_sai_set_iec958_status(sai, substream->runtime);
1083*4882a593Smuzhiyun 	} else {
1084*4882a593Smuzhiyun 		ret = stm32_sai_set_slots(cpu_dai);
1085*4882a593Smuzhiyun 		if (ret < 0)
1086*4882a593Smuzhiyun 			return ret;
1087*4882a593Smuzhiyun 		stm32_sai_set_frame(cpu_dai);
1088*4882a593Smuzhiyun 	}
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	ret = stm32_sai_set_config(cpu_dai, substream, params);
1091*4882a593Smuzhiyun 	if (ret)
1092*4882a593Smuzhiyun 		return ret;
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	if (sai->master)
1095*4882a593Smuzhiyun 		ret = stm32_sai_configure_clock(cpu_dai, params);
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 	return ret;
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun 
stm32_sai_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * cpu_dai)1100*4882a593Smuzhiyun static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
1101*4882a593Smuzhiyun 			     struct snd_soc_dai *cpu_dai)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
1104*4882a593Smuzhiyun 	int ret;
1105*4882a593Smuzhiyun 
1106*4882a593Smuzhiyun 	switch (cmd) {
1107*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_START:
1108*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_RESUME:
1109*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1110*4882a593Smuzhiyun 		dev_dbg(cpu_dai->dev, "Enable DMA and SAI\n");
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 		stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
1113*4882a593Smuzhiyun 				     SAI_XCR1_DMAEN, SAI_XCR1_DMAEN);
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 		/* Enable SAI */
1116*4882a593Smuzhiyun 		ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
1117*4882a593Smuzhiyun 					   SAI_XCR1_SAIEN, SAI_XCR1_SAIEN);
1118*4882a593Smuzhiyun 		if (ret < 0)
1119*4882a593Smuzhiyun 			dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
1120*4882a593Smuzhiyun 		break;
1121*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_SUSPEND:
1122*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1123*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_STOP:
1124*4882a593Smuzhiyun 		dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
1125*4882a593Smuzhiyun 
1126*4882a593Smuzhiyun 		stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX,
1127*4882a593Smuzhiyun 				     SAI_XIMR_MASK, 0);
1128*4882a593Smuzhiyun 
1129*4882a593Smuzhiyun 		stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
1130*4882a593Smuzhiyun 				     SAI_XCR1_SAIEN,
1131*4882a593Smuzhiyun 				     (unsigned int)~SAI_XCR1_SAIEN);
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 		ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX,
1134*4882a593Smuzhiyun 					   SAI_XCR1_DMAEN,
1135*4882a593Smuzhiyun 					   (unsigned int)~SAI_XCR1_DMAEN);
1136*4882a593Smuzhiyun 		if (ret < 0)
1137*4882a593Smuzhiyun 			dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 		if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
1140*4882a593Smuzhiyun 			sai->spdif_frm_cnt = 0;
1141*4882a593Smuzhiyun 		break;
1142*4882a593Smuzhiyun 	default:
1143*4882a593Smuzhiyun 		return -EINVAL;
1144*4882a593Smuzhiyun 	}
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun 	return ret;
1147*4882a593Smuzhiyun }
1148*4882a593Smuzhiyun 
stm32_sai_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)1149*4882a593Smuzhiyun static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
1150*4882a593Smuzhiyun 			       struct snd_soc_dai *cpu_dai)
1151*4882a593Smuzhiyun {
1152*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
1153*4882a593Smuzhiyun 	unsigned long flags;
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun 	clk_disable_unprepare(sai->sai_ck);
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun 	spin_lock_irqsave(&sai->irq_lock, flags);
1160*4882a593Smuzhiyun 	sai->substream = NULL;
1161*4882a593Smuzhiyun 	spin_unlock_irqrestore(&sai->irq_lock, flags);
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun 
stm32_sai_pcm_new(struct snd_soc_pcm_runtime * rtd,struct snd_soc_dai * cpu_dai)1164*4882a593Smuzhiyun static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd,
1165*4882a593Smuzhiyun 			     struct snd_soc_dai *cpu_dai)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
1168*4882a593Smuzhiyun 	struct snd_kcontrol_new knew = iec958_ctls;
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) {
1171*4882a593Smuzhiyun 		dev_dbg(&sai->pdev->dev, "%s: register iec controls", __func__);
1172*4882a593Smuzhiyun 		knew.device = rtd->pcm->device;
1173*4882a593Smuzhiyun 		return snd_ctl_add(rtd->pcm->card, snd_ctl_new1(&knew, sai));
1174*4882a593Smuzhiyun 	}
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	return 0;
1177*4882a593Smuzhiyun }
1178*4882a593Smuzhiyun 
stm32_sai_dai_probe(struct snd_soc_dai * cpu_dai)1179*4882a593Smuzhiyun static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
1180*4882a593Smuzhiyun {
1181*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
1182*4882a593Smuzhiyun 	int cr1 = 0, cr1_mask, ret;
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun 	sai->cpu_dai = cpu_dai;
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 	sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
1187*4882a593Smuzhiyun 	/*
1188*4882a593Smuzhiyun 	 * DMA supports 4, 8 or 16 burst sizes. Burst size 4 is the best choice,
1189*4882a593Smuzhiyun 	 * as it allows bytes, half-word and words transfers. (See DMA fifos
1190*4882a593Smuzhiyun 	 * constraints).
1191*4882a593Smuzhiyun 	 */
1192*4882a593Smuzhiyun 	sai->dma_params.maxburst = 4;
1193*4882a593Smuzhiyun 	if (sai->pdata->conf.fifo_size < 8)
1194*4882a593Smuzhiyun 		sai->dma_params.maxburst = 1;
1195*4882a593Smuzhiyun 	/* Buswidth will be set by framework at runtime */
1196*4882a593Smuzhiyun 	sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	if (STM_SAI_IS_PLAYBACK(sai))
1199*4882a593Smuzhiyun 		snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params, NULL);
1200*4882a593Smuzhiyun 	else
1201*4882a593Smuzhiyun 		snd_soc_dai_init_dma_data(cpu_dai, NULL, &sai->dma_params);
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	/* Next settings are not relevant for spdif mode */
1204*4882a593Smuzhiyun 	if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
1205*4882a593Smuzhiyun 		return 0;
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun 	cr1_mask = SAI_XCR1_RX_TX;
1208*4882a593Smuzhiyun 	if (STM_SAI_IS_CAPTURE(sai))
1209*4882a593Smuzhiyun 		cr1 |= SAI_XCR1_RX_TX;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	/* Configure synchronization */
1212*4882a593Smuzhiyun 	if (sai->sync == SAI_SYNC_EXTERNAL) {
1213*4882a593Smuzhiyun 		/* Configure synchro client and provider */
1214*4882a593Smuzhiyun 		ret = sai->pdata->set_sync(sai->pdata, sai->np_sync_provider,
1215*4882a593Smuzhiyun 					   sai->synco, sai->synci);
1216*4882a593Smuzhiyun 		if (ret)
1217*4882a593Smuzhiyun 			return ret;
1218*4882a593Smuzhiyun 	}
1219*4882a593Smuzhiyun 
1220*4882a593Smuzhiyun 	cr1_mask |= SAI_XCR1_SYNCEN_MASK;
1221*4882a593Smuzhiyun 	cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync);
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 	return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1);
1224*4882a593Smuzhiyun }
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
1227*4882a593Smuzhiyun 	.set_sysclk	= stm32_sai_set_sysclk,
1228*4882a593Smuzhiyun 	.set_fmt	= stm32_sai_set_dai_fmt,
1229*4882a593Smuzhiyun 	.set_tdm_slot	= stm32_sai_set_dai_tdm_slot,
1230*4882a593Smuzhiyun 	.startup	= stm32_sai_startup,
1231*4882a593Smuzhiyun 	.hw_params	= stm32_sai_hw_params,
1232*4882a593Smuzhiyun 	.trigger	= stm32_sai_trigger,
1233*4882a593Smuzhiyun 	.shutdown	= stm32_sai_shutdown,
1234*4882a593Smuzhiyun };
1235*4882a593Smuzhiyun 
stm32_sai_pcm_process_spdif(struct snd_pcm_substream * substream,int channel,unsigned long hwoff,void * buf,unsigned long bytes)1236*4882a593Smuzhiyun static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream,
1237*4882a593Smuzhiyun 				       int channel, unsigned long hwoff,
1238*4882a593Smuzhiyun 				       void *buf, unsigned long bytes)
1239*4882a593Smuzhiyun {
1240*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
1241*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
1242*4882a593Smuzhiyun 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
1243*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
1244*4882a593Smuzhiyun 	int *ptr = (int *)(runtime->dma_area + hwoff +
1245*4882a593Smuzhiyun 			   channel * (runtime->dma_bytes / runtime->channels));
1246*4882a593Smuzhiyun 	ssize_t cnt = bytes_to_samples(runtime, bytes);
1247*4882a593Smuzhiyun 	unsigned int frm_cnt = sai->spdif_frm_cnt;
1248*4882a593Smuzhiyun 	unsigned int byte;
1249*4882a593Smuzhiyun 	unsigned int mask;
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	do {
1252*4882a593Smuzhiyun 		*ptr = ((*ptr >> 8) & 0x00ffffff);
1253*4882a593Smuzhiyun 
1254*4882a593Smuzhiyun 		/* Set channel status bit */
1255*4882a593Smuzhiyun 		byte = frm_cnt >> 3;
1256*4882a593Smuzhiyun 		mask = 1 << (frm_cnt - (byte << 3));
1257*4882a593Smuzhiyun 		if (sai->iec958.status[byte] & mask)
1258*4882a593Smuzhiyun 			*ptr |= 0x04000000;
1259*4882a593Smuzhiyun 		ptr++;
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun 		if (!(cnt % 2))
1262*4882a593Smuzhiyun 			frm_cnt++;
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 		if (frm_cnt == SAI_IEC60958_BLOCK_FRAMES)
1265*4882a593Smuzhiyun 			frm_cnt = 0;
1266*4882a593Smuzhiyun 	} while (--cnt);
1267*4882a593Smuzhiyun 	sai->spdif_frm_cnt = frm_cnt;
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun 	return 0;
1270*4882a593Smuzhiyun }
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun /* No support of mmap in S/PDIF mode */
1273*4882a593Smuzhiyun static const struct snd_pcm_hardware stm32_sai_pcm_hw_spdif = {
1274*4882a593Smuzhiyun 	.info = SNDRV_PCM_INFO_INTERLEAVED,
1275*4882a593Smuzhiyun 	.buffer_bytes_max = 8 * PAGE_SIZE,
1276*4882a593Smuzhiyun 	.period_bytes_min = 1024,
1277*4882a593Smuzhiyun 	.period_bytes_max = PAGE_SIZE,
1278*4882a593Smuzhiyun 	.periods_min = 2,
1279*4882a593Smuzhiyun 	.periods_max = 8,
1280*4882a593Smuzhiyun };
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
1283*4882a593Smuzhiyun 	.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
1284*4882a593Smuzhiyun 	.buffer_bytes_max = 8 * PAGE_SIZE,
1285*4882a593Smuzhiyun 	.period_bytes_min = 1024, /* 5ms at 48kHz */
1286*4882a593Smuzhiyun 	.period_bytes_max = PAGE_SIZE,
1287*4882a593Smuzhiyun 	.periods_min = 2,
1288*4882a593Smuzhiyun 	.periods_max = 8,
1289*4882a593Smuzhiyun };
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun static struct snd_soc_dai_driver stm32_sai_playback_dai = {
1292*4882a593Smuzhiyun 		.probe = stm32_sai_dai_probe,
1293*4882a593Smuzhiyun 		.pcm_new = stm32_sai_pcm_new,
1294*4882a593Smuzhiyun 		.id = 1, /* avoid call to fmt_single_name() */
1295*4882a593Smuzhiyun 		.playback = {
1296*4882a593Smuzhiyun 			.channels_min = 1,
1297*4882a593Smuzhiyun 			.channels_max = 2,
1298*4882a593Smuzhiyun 			.rate_min = 8000,
1299*4882a593Smuzhiyun 			.rate_max = 192000,
1300*4882a593Smuzhiyun 			.rates = SNDRV_PCM_RATE_CONTINUOUS,
1301*4882a593Smuzhiyun 			/* DMA does not support 24 bits transfers */
1302*4882a593Smuzhiyun 			.formats =
1303*4882a593Smuzhiyun 				SNDRV_PCM_FMTBIT_S8 |
1304*4882a593Smuzhiyun 				SNDRV_PCM_FMTBIT_S16_LE |
1305*4882a593Smuzhiyun 				SNDRV_PCM_FMTBIT_S32_LE,
1306*4882a593Smuzhiyun 		},
1307*4882a593Smuzhiyun 		.ops = &stm32_sai_pcm_dai_ops,
1308*4882a593Smuzhiyun };
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun static struct snd_soc_dai_driver stm32_sai_capture_dai = {
1311*4882a593Smuzhiyun 		.probe = stm32_sai_dai_probe,
1312*4882a593Smuzhiyun 		.id = 1, /* avoid call to fmt_single_name() */
1313*4882a593Smuzhiyun 		.capture = {
1314*4882a593Smuzhiyun 			.channels_min = 1,
1315*4882a593Smuzhiyun 			.channels_max = 2,
1316*4882a593Smuzhiyun 			.rate_min = 8000,
1317*4882a593Smuzhiyun 			.rate_max = 192000,
1318*4882a593Smuzhiyun 			.rates = SNDRV_PCM_RATE_CONTINUOUS,
1319*4882a593Smuzhiyun 			/* DMA does not support 24 bits transfers */
1320*4882a593Smuzhiyun 			.formats =
1321*4882a593Smuzhiyun 				SNDRV_PCM_FMTBIT_S8 |
1322*4882a593Smuzhiyun 				SNDRV_PCM_FMTBIT_S16_LE |
1323*4882a593Smuzhiyun 				SNDRV_PCM_FMTBIT_S32_LE,
1324*4882a593Smuzhiyun 		},
1325*4882a593Smuzhiyun 		.ops = &stm32_sai_pcm_dai_ops,
1326*4882a593Smuzhiyun };
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = {
1329*4882a593Smuzhiyun 	.pcm_hardware = &stm32_sai_pcm_hw,
1330*4882a593Smuzhiyun 	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
1331*4882a593Smuzhiyun };
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config_spdif = {
1334*4882a593Smuzhiyun 	.pcm_hardware = &stm32_sai_pcm_hw_spdif,
1335*4882a593Smuzhiyun 	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
1336*4882a593Smuzhiyun 	.process = stm32_sai_pcm_process_spdif,
1337*4882a593Smuzhiyun };
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun static const struct snd_soc_component_driver stm32_component = {
1340*4882a593Smuzhiyun 	.name = "stm32-sai",
1341*4882a593Smuzhiyun };
1342*4882a593Smuzhiyun 
1343*4882a593Smuzhiyun static const struct of_device_id stm32_sai_sub_ids[] = {
1344*4882a593Smuzhiyun 	{ .compatible = "st,stm32-sai-sub-a",
1345*4882a593Smuzhiyun 	  .data = (void *)STM_SAI_A_ID},
1346*4882a593Smuzhiyun 	{ .compatible = "st,stm32-sai-sub-b",
1347*4882a593Smuzhiyun 	  .data = (void *)STM_SAI_B_ID},
1348*4882a593Smuzhiyun 	{}
1349*4882a593Smuzhiyun };
1350*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, stm32_sai_sub_ids);
1351*4882a593Smuzhiyun 
stm32_sai_sub_parse_of(struct platform_device * pdev,struct stm32_sai_sub_data * sai)1352*4882a593Smuzhiyun static int stm32_sai_sub_parse_of(struct platform_device *pdev,
1353*4882a593Smuzhiyun 				  struct stm32_sai_sub_data *sai)
1354*4882a593Smuzhiyun {
1355*4882a593Smuzhiyun 	struct device_node *np = pdev->dev.of_node;
1356*4882a593Smuzhiyun 	struct resource *res;
1357*4882a593Smuzhiyun 	void __iomem *base;
1358*4882a593Smuzhiyun 	struct of_phandle_args args;
1359*4882a593Smuzhiyun 	int ret;
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun 	if (!np)
1362*4882a593Smuzhiyun 		return -ENODEV;
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1365*4882a593Smuzhiyun 	base = devm_ioremap_resource(&pdev->dev, res);
1366*4882a593Smuzhiyun 	if (IS_ERR(base))
1367*4882a593Smuzhiyun 		return PTR_ERR(base);
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	sai->phys_addr = res->start;
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun 	sai->regmap_config = &stm32_sai_sub_regmap_config_f4;
1372*4882a593Smuzhiyun 	/* Note: PDM registers not available for sub-block B */
1373*4882a593Smuzhiyun 	if (STM_SAI_HAS_PDM(sai) && STM_SAI_IS_SUB_A(sai))
1374*4882a593Smuzhiyun 		sai->regmap_config = &stm32_sai_sub_regmap_config_h7;
1375*4882a593Smuzhiyun 
1376*4882a593Smuzhiyun 	/*
1377*4882a593Smuzhiyun 	 * Do not manage peripheral clock through regmap framework as this
1378*4882a593Smuzhiyun 	 * can lead to circular locking issue with sai master clock provider.
1379*4882a593Smuzhiyun 	 * Manage peripheral clock directly in driver instead.
1380*4882a593Smuzhiyun 	 */
1381*4882a593Smuzhiyun 	sai->regmap = devm_regmap_init_mmio(&pdev->dev, base,
1382*4882a593Smuzhiyun 					    sai->regmap_config);
1383*4882a593Smuzhiyun 	if (IS_ERR(sai->regmap)) {
1384*4882a593Smuzhiyun 		if (PTR_ERR(sai->regmap) != -EPROBE_DEFER)
1385*4882a593Smuzhiyun 			dev_err(&pdev->dev, "Regmap init error %ld\n",
1386*4882a593Smuzhiyun 				PTR_ERR(sai->regmap));
1387*4882a593Smuzhiyun 		return PTR_ERR(sai->regmap);
1388*4882a593Smuzhiyun 	}
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	/* Get direction property */
1391*4882a593Smuzhiyun 	if (of_property_match_string(np, "dma-names", "tx") >= 0) {
1392*4882a593Smuzhiyun 		sai->dir = SNDRV_PCM_STREAM_PLAYBACK;
1393*4882a593Smuzhiyun 	} else if (of_property_match_string(np, "dma-names", "rx") >= 0) {
1394*4882a593Smuzhiyun 		sai->dir = SNDRV_PCM_STREAM_CAPTURE;
1395*4882a593Smuzhiyun 	} else {
1396*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Unsupported direction\n");
1397*4882a593Smuzhiyun 		return -EINVAL;
1398*4882a593Smuzhiyun 	}
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun 	/* Get spdif iec60958 property */
1401*4882a593Smuzhiyun 	sai->spdif = false;
1402*4882a593Smuzhiyun 	if (of_get_property(np, "st,iec60958", NULL)) {
1403*4882a593Smuzhiyun 		if (!STM_SAI_HAS_SPDIF(sai) ||
1404*4882a593Smuzhiyun 		    sai->dir == SNDRV_PCM_STREAM_CAPTURE) {
1405*4882a593Smuzhiyun 			dev_err(&pdev->dev, "S/PDIF IEC60958 not supported\n");
1406*4882a593Smuzhiyun 			return -EINVAL;
1407*4882a593Smuzhiyun 		}
1408*4882a593Smuzhiyun 		stm32_sai_init_iec958_status(sai);
1409*4882a593Smuzhiyun 		sai->spdif = true;
1410*4882a593Smuzhiyun 		sai->master = true;
1411*4882a593Smuzhiyun 	}
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 	/* Get synchronization property */
1414*4882a593Smuzhiyun 	args.np = NULL;
1415*4882a593Smuzhiyun 	ret = of_parse_phandle_with_fixed_args(np, "st,sync", 1, 0, &args);
1416*4882a593Smuzhiyun 	if (ret < 0  && ret != -ENOENT) {
1417*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Failed to get st,sync property\n");
1418*4882a593Smuzhiyun 		return ret;
1419*4882a593Smuzhiyun 	}
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	sai->sync = SAI_SYNC_NONE;
1422*4882a593Smuzhiyun 	if (args.np) {
1423*4882a593Smuzhiyun 		if (args.np == np) {
1424*4882a593Smuzhiyun 			dev_err(&pdev->dev, "%pOFn sync own reference\n", np);
1425*4882a593Smuzhiyun 			of_node_put(args.np);
1426*4882a593Smuzhiyun 			return -EINVAL;
1427*4882a593Smuzhiyun 		}
1428*4882a593Smuzhiyun 
1429*4882a593Smuzhiyun 		sai->np_sync_provider  = of_get_parent(args.np);
1430*4882a593Smuzhiyun 		if (!sai->np_sync_provider) {
1431*4882a593Smuzhiyun 			dev_err(&pdev->dev, "%pOFn parent node not found\n",
1432*4882a593Smuzhiyun 				np);
1433*4882a593Smuzhiyun 			of_node_put(args.np);
1434*4882a593Smuzhiyun 			return -ENODEV;
1435*4882a593Smuzhiyun 		}
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 		sai->sync = SAI_SYNC_INTERNAL;
1438*4882a593Smuzhiyun 		if (sai->np_sync_provider != sai->pdata->pdev->dev.of_node) {
1439*4882a593Smuzhiyun 			if (!STM_SAI_HAS_EXT_SYNC(sai)) {
1440*4882a593Smuzhiyun 				dev_err(&pdev->dev,
1441*4882a593Smuzhiyun 					"External synchro not supported\n");
1442*4882a593Smuzhiyun 				of_node_put(args.np);
1443*4882a593Smuzhiyun 				return -EINVAL;
1444*4882a593Smuzhiyun 			}
1445*4882a593Smuzhiyun 			sai->sync = SAI_SYNC_EXTERNAL;
1446*4882a593Smuzhiyun 
1447*4882a593Smuzhiyun 			sai->synci = args.args[0];
1448*4882a593Smuzhiyun 			if (sai->synci < 1 ||
1449*4882a593Smuzhiyun 			    (sai->synci > (SAI_GCR_SYNCIN_MAX + 1))) {
1450*4882a593Smuzhiyun 				dev_err(&pdev->dev, "Wrong SAI index\n");
1451*4882a593Smuzhiyun 				of_node_put(args.np);
1452*4882a593Smuzhiyun 				return -EINVAL;
1453*4882a593Smuzhiyun 			}
1454*4882a593Smuzhiyun 
1455*4882a593Smuzhiyun 			if (of_property_match_string(args.np, "compatible",
1456*4882a593Smuzhiyun 						     "st,stm32-sai-sub-a") >= 0)
1457*4882a593Smuzhiyun 				sai->synco = STM_SAI_SYNC_OUT_A;
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 			if (of_property_match_string(args.np, "compatible",
1460*4882a593Smuzhiyun 						     "st,stm32-sai-sub-b") >= 0)
1461*4882a593Smuzhiyun 				sai->synco = STM_SAI_SYNC_OUT_B;
1462*4882a593Smuzhiyun 
1463*4882a593Smuzhiyun 			if (!sai->synco) {
1464*4882a593Smuzhiyun 				dev_err(&pdev->dev, "Unknown SAI sub-block\n");
1465*4882a593Smuzhiyun 				of_node_put(args.np);
1466*4882a593Smuzhiyun 				return -EINVAL;
1467*4882a593Smuzhiyun 			}
1468*4882a593Smuzhiyun 		}
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun 		dev_dbg(&pdev->dev, "%s synchronized with %s\n",
1471*4882a593Smuzhiyun 			pdev->name, args.np->full_name);
1472*4882a593Smuzhiyun 	}
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun 	of_node_put(args.np);
1475*4882a593Smuzhiyun 	sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
1476*4882a593Smuzhiyun 	if (IS_ERR(sai->sai_ck)) {
1477*4882a593Smuzhiyun 		if (PTR_ERR(sai->sai_ck) != -EPROBE_DEFER)
1478*4882a593Smuzhiyun 			dev_err(&pdev->dev, "Missing kernel clock sai_ck: %ld\n",
1479*4882a593Smuzhiyun 				PTR_ERR(sai->sai_ck));
1480*4882a593Smuzhiyun 		return PTR_ERR(sai->sai_ck);
1481*4882a593Smuzhiyun 	}
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 	ret = clk_prepare(sai->pdata->pclk);
1484*4882a593Smuzhiyun 	if (ret < 0)
1485*4882a593Smuzhiyun 		return ret;
1486*4882a593Smuzhiyun 
1487*4882a593Smuzhiyun 	if (STM_SAI_IS_F4(sai->pdata))
1488*4882a593Smuzhiyun 		return 0;
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun 	/* Register mclk provider if requested */
1491*4882a593Smuzhiyun 	if (of_find_property(np, "#clock-cells", NULL)) {
1492*4882a593Smuzhiyun 		ret = stm32_sai_add_mclk_provider(sai);
1493*4882a593Smuzhiyun 		if (ret < 0)
1494*4882a593Smuzhiyun 			return ret;
1495*4882a593Smuzhiyun 	} else {
1496*4882a593Smuzhiyun 		sai->sai_mclk = devm_clk_get(&pdev->dev, "MCLK");
1497*4882a593Smuzhiyun 		if (IS_ERR(sai->sai_mclk)) {
1498*4882a593Smuzhiyun 			if (PTR_ERR(sai->sai_mclk) != -ENOENT)
1499*4882a593Smuzhiyun 				return PTR_ERR(sai->sai_mclk);
1500*4882a593Smuzhiyun 			sai->sai_mclk = NULL;
1501*4882a593Smuzhiyun 		}
1502*4882a593Smuzhiyun 	}
1503*4882a593Smuzhiyun 
1504*4882a593Smuzhiyun 	return 0;
1505*4882a593Smuzhiyun }
1506*4882a593Smuzhiyun 
stm32_sai_sub_probe(struct platform_device * pdev)1507*4882a593Smuzhiyun static int stm32_sai_sub_probe(struct platform_device *pdev)
1508*4882a593Smuzhiyun {
1509*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai;
1510*4882a593Smuzhiyun 	const struct of_device_id *of_id;
1511*4882a593Smuzhiyun 	const struct snd_dmaengine_pcm_config *conf = &stm32_sai_pcm_config;
1512*4882a593Smuzhiyun 	int ret;
1513*4882a593Smuzhiyun 
1514*4882a593Smuzhiyun 	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
1515*4882a593Smuzhiyun 	if (!sai)
1516*4882a593Smuzhiyun 		return -ENOMEM;
1517*4882a593Smuzhiyun 
1518*4882a593Smuzhiyun 	of_id = of_match_device(stm32_sai_sub_ids, &pdev->dev);
1519*4882a593Smuzhiyun 	if (!of_id)
1520*4882a593Smuzhiyun 		return -EINVAL;
1521*4882a593Smuzhiyun 	sai->id = (uintptr_t)of_id->data;
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun 	sai->pdev = pdev;
1524*4882a593Smuzhiyun 	mutex_init(&sai->ctrl_lock);
1525*4882a593Smuzhiyun 	spin_lock_init(&sai->irq_lock);
1526*4882a593Smuzhiyun 	platform_set_drvdata(pdev, sai);
1527*4882a593Smuzhiyun 
1528*4882a593Smuzhiyun 	sai->pdata = dev_get_drvdata(pdev->dev.parent);
1529*4882a593Smuzhiyun 	if (!sai->pdata) {
1530*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Parent device data not available\n");
1531*4882a593Smuzhiyun 		return -EINVAL;
1532*4882a593Smuzhiyun 	}
1533*4882a593Smuzhiyun 
1534*4882a593Smuzhiyun 	ret = stm32_sai_sub_parse_of(pdev, sai);
1535*4882a593Smuzhiyun 	if (ret)
1536*4882a593Smuzhiyun 		return ret;
1537*4882a593Smuzhiyun 
1538*4882a593Smuzhiyun 	if (STM_SAI_IS_PLAYBACK(sai))
1539*4882a593Smuzhiyun 		sai->cpu_dai_drv = stm32_sai_playback_dai;
1540*4882a593Smuzhiyun 	else
1541*4882a593Smuzhiyun 		sai->cpu_dai_drv = stm32_sai_capture_dai;
1542*4882a593Smuzhiyun 	sai->cpu_dai_drv.name = dev_name(&pdev->dev);
1543*4882a593Smuzhiyun 
1544*4882a593Smuzhiyun 	ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr,
1545*4882a593Smuzhiyun 			       IRQF_SHARED, dev_name(&pdev->dev), sai);
1546*4882a593Smuzhiyun 	if (ret) {
1547*4882a593Smuzhiyun 		dev_err(&pdev->dev, "IRQ request returned %d\n", ret);
1548*4882a593Smuzhiyun 		return ret;
1549*4882a593Smuzhiyun 	}
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 	if (STM_SAI_PROTOCOL_IS_SPDIF(sai))
1552*4882a593Smuzhiyun 		conf = &stm32_sai_pcm_config_spdif;
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 	ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0);
1555*4882a593Smuzhiyun 	if (ret) {
1556*4882a593Smuzhiyun 		if (ret != -EPROBE_DEFER)
1557*4882a593Smuzhiyun 			dev_err(&pdev->dev, "Could not register pcm dma\n");
1558*4882a593Smuzhiyun 		return ret;
1559*4882a593Smuzhiyun 	}
1560*4882a593Smuzhiyun 
1561*4882a593Smuzhiyun 	ret = snd_soc_register_component(&pdev->dev, &stm32_component,
1562*4882a593Smuzhiyun 					 &sai->cpu_dai_drv, 1);
1563*4882a593Smuzhiyun 	if (ret) {
1564*4882a593Smuzhiyun 		snd_dmaengine_pcm_unregister(&pdev->dev);
1565*4882a593Smuzhiyun 		return ret;
1566*4882a593Smuzhiyun 	}
1567*4882a593Smuzhiyun 
1568*4882a593Smuzhiyun 	pm_runtime_enable(&pdev->dev);
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun 	return 0;
1571*4882a593Smuzhiyun }
1572*4882a593Smuzhiyun 
stm32_sai_sub_remove(struct platform_device * pdev)1573*4882a593Smuzhiyun static int stm32_sai_sub_remove(struct platform_device *pdev)
1574*4882a593Smuzhiyun {
1575*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = dev_get_drvdata(&pdev->dev);
1576*4882a593Smuzhiyun 
1577*4882a593Smuzhiyun 	clk_unprepare(sai->pdata->pclk);
1578*4882a593Smuzhiyun 	snd_dmaengine_pcm_unregister(&pdev->dev);
1579*4882a593Smuzhiyun 	snd_soc_unregister_component(&pdev->dev);
1580*4882a593Smuzhiyun 	pm_runtime_disable(&pdev->dev);
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 	return 0;
1583*4882a593Smuzhiyun }
1584*4882a593Smuzhiyun 
1585*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
stm32_sai_sub_suspend(struct device * dev)1586*4882a593Smuzhiyun static int stm32_sai_sub_suspend(struct device *dev)
1587*4882a593Smuzhiyun {
1588*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = dev_get_drvdata(dev);
1589*4882a593Smuzhiyun 	int ret;
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun 	ret = clk_enable(sai->pdata->pclk);
1592*4882a593Smuzhiyun 	if (ret < 0)
1593*4882a593Smuzhiyun 		return ret;
1594*4882a593Smuzhiyun 
1595*4882a593Smuzhiyun 	regcache_cache_only(sai->regmap, true);
1596*4882a593Smuzhiyun 	regcache_mark_dirty(sai->regmap);
1597*4882a593Smuzhiyun 
1598*4882a593Smuzhiyun 	clk_disable(sai->pdata->pclk);
1599*4882a593Smuzhiyun 
1600*4882a593Smuzhiyun 	return 0;
1601*4882a593Smuzhiyun }
1602*4882a593Smuzhiyun 
stm32_sai_sub_resume(struct device * dev)1603*4882a593Smuzhiyun static int stm32_sai_sub_resume(struct device *dev)
1604*4882a593Smuzhiyun {
1605*4882a593Smuzhiyun 	struct stm32_sai_sub_data *sai = dev_get_drvdata(dev);
1606*4882a593Smuzhiyun 	int ret;
1607*4882a593Smuzhiyun 
1608*4882a593Smuzhiyun 	ret = clk_enable(sai->pdata->pclk);
1609*4882a593Smuzhiyun 	if (ret < 0)
1610*4882a593Smuzhiyun 		return ret;
1611*4882a593Smuzhiyun 
1612*4882a593Smuzhiyun 	regcache_cache_only(sai->regmap, false);
1613*4882a593Smuzhiyun 	ret = regcache_sync(sai->regmap);
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun 	clk_disable(sai->pdata->pclk);
1616*4882a593Smuzhiyun 
1617*4882a593Smuzhiyun 	return ret;
1618*4882a593Smuzhiyun }
1619*4882a593Smuzhiyun #endif /* CONFIG_PM_SLEEP */
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun static const struct dev_pm_ops stm32_sai_sub_pm_ops = {
1622*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_sub_suspend, stm32_sai_sub_resume)
1623*4882a593Smuzhiyun };
1624*4882a593Smuzhiyun 
1625*4882a593Smuzhiyun static struct platform_driver stm32_sai_sub_driver = {
1626*4882a593Smuzhiyun 	.driver = {
1627*4882a593Smuzhiyun 		.name = "st,stm32-sai-sub",
1628*4882a593Smuzhiyun 		.of_match_table = stm32_sai_sub_ids,
1629*4882a593Smuzhiyun 		.pm = &stm32_sai_sub_pm_ops,
1630*4882a593Smuzhiyun 	},
1631*4882a593Smuzhiyun 	.probe = stm32_sai_sub_probe,
1632*4882a593Smuzhiyun 	.remove = stm32_sai_sub_remove,
1633*4882a593Smuzhiyun };
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun module_platform_driver(stm32_sai_sub_driver);
1636*4882a593Smuzhiyun 
1637*4882a593Smuzhiyun MODULE_DESCRIPTION("STM32 Soc SAI sub-block Interface");
1638*4882a593Smuzhiyun MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
1639*4882a593Smuzhiyun MODULE_ALIAS("platform:st,stm32-sai-sub");
1640*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1641