xref: /OK3568_Linux_fs/kernel/sound/soc/ux500/ux500_msp_dai.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) ST-Ericsson SA 2012
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
6*4882a593Smuzhiyun  *         Roger Nilsson <roger.xr.nilsson@stericsson.com>
7*4882a593Smuzhiyun  *         for ST-Ericsson.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * License terms:
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/bitops.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/clk.h>
17*4882a593Smuzhiyun #include <linux/of.h>
18*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
19*4882a593Smuzhiyun #include <linux/mfd/dbx500-prcmu.h>
20*4882a593Smuzhiyun #include <linux/platform_data/asoc-ux500-msp.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include <sound/soc.h>
23*4882a593Smuzhiyun #include <sound/soc-dai.h>
24*4882a593Smuzhiyun #include <sound/dmaengine_pcm.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include "ux500_msp_i2s.h"
27*4882a593Smuzhiyun #include "ux500_msp_dai.h"
28*4882a593Smuzhiyun #include "ux500_pcm.h"
29*4882a593Smuzhiyun 
setup_pcm_multichan(struct snd_soc_dai * dai,struct ux500_msp_config * msp_config)30*4882a593Smuzhiyun static int setup_pcm_multichan(struct snd_soc_dai *dai,
31*4882a593Smuzhiyun 			struct ux500_msp_config *msp_config)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
34*4882a593Smuzhiyun 	struct msp_multichannel_config *multi =
35*4882a593Smuzhiyun 					&msp_config->multichannel_config;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	if (drvdata->slots > 1) {
38*4882a593Smuzhiyun 		msp_config->multichannel_configured = 1;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 		multi->tx_multichannel_enable = true;
41*4882a593Smuzhiyun 		multi->rx_multichannel_enable = true;
42*4882a593Smuzhiyun 		multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 		multi->tx_channel_0_enable = drvdata->tx_mask;
45*4882a593Smuzhiyun 		multi->tx_channel_1_enable = 0;
46*4882a593Smuzhiyun 		multi->tx_channel_2_enable = 0;
47*4882a593Smuzhiyun 		multi->tx_channel_3_enable = 0;
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 		multi->rx_channel_0_enable = drvdata->rx_mask;
50*4882a593Smuzhiyun 		multi->rx_channel_1_enable = 0;
51*4882a593Smuzhiyun 		multi->rx_channel_2_enable = 0;
52*4882a593Smuzhiyun 		multi->rx_channel_3_enable = 0;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 		dev_dbg(dai->dev,
55*4882a593Smuzhiyun 			"%s: Multichannel enabled. Slots: %d, TX: %u, RX: %u\n",
56*4882a593Smuzhiyun 			__func__, drvdata->slots, multi->tx_channel_0_enable,
57*4882a593Smuzhiyun 			multi->rx_channel_0_enable);
58*4882a593Smuzhiyun 	}
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	return 0;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
setup_frameper(struct snd_soc_dai * dai,unsigned int rate,struct msp_protdesc * prot_desc)63*4882a593Smuzhiyun static int setup_frameper(struct snd_soc_dai *dai, unsigned int rate,
64*4882a593Smuzhiyun 			struct msp_protdesc *prot_desc)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	switch (drvdata->slots) {
69*4882a593Smuzhiyun 	case 1:
70*4882a593Smuzhiyun 		switch (rate) {
71*4882a593Smuzhiyun 		case 8000:
72*4882a593Smuzhiyun 			prot_desc->frame_period =
73*4882a593Smuzhiyun 				FRAME_PER_SINGLE_SLOT_8_KHZ;
74*4882a593Smuzhiyun 			break;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 		case 16000:
77*4882a593Smuzhiyun 			prot_desc->frame_period =
78*4882a593Smuzhiyun 				FRAME_PER_SINGLE_SLOT_16_KHZ;
79*4882a593Smuzhiyun 			break;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 		case 44100:
82*4882a593Smuzhiyun 			prot_desc->frame_period =
83*4882a593Smuzhiyun 				FRAME_PER_SINGLE_SLOT_44_1_KHZ;
84*4882a593Smuzhiyun 			break;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 		case 48000:
87*4882a593Smuzhiyun 			prot_desc->frame_period =
88*4882a593Smuzhiyun 				FRAME_PER_SINGLE_SLOT_48_KHZ;
89*4882a593Smuzhiyun 			break;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 		default:
92*4882a593Smuzhiyun 			dev_err(dai->dev,
93*4882a593Smuzhiyun 				"%s: Error: Unsupported sample-rate (freq = %d)!\n",
94*4882a593Smuzhiyun 				__func__, rate);
95*4882a593Smuzhiyun 			return -EINVAL;
96*4882a593Smuzhiyun 		}
97*4882a593Smuzhiyun 		break;
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	case 2:
100*4882a593Smuzhiyun 		prot_desc->frame_period = FRAME_PER_2_SLOTS;
101*4882a593Smuzhiyun 		break;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	case 8:
104*4882a593Smuzhiyun 		prot_desc->frame_period = FRAME_PER_8_SLOTS;
105*4882a593Smuzhiyun 		break;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	case 16:
108*4882a593Smuzhiyun 		prot_desc->frame_period = FRAME_PER_16_SLOTS;
109*4882a593Smuzhiyun 		break;
110*4882a593Smuzhiyun 	default:
111*4882a593Smuzhiyun 		dev_err(dai->dev,
112*4882a593Smuzhiyun 			"%s: Error: Unsupported slot-count (slots = %d)!\n",
113*4882a593Smuzhiyun 			__func__, drvdata->slots);
114*4882a593Smuzhiyun 		return -EINVAL;
115*4882a593Smuzhiyun 	}
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	prot_desc->clocks_per_frame =
118*4882a593Smuzhiyun 			prot_desc->frame_period+1;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: Clocks per frame: %u\n",
121*4882a593Smuzhiyun 		__func__,
122*4882a593Smuzhiyun 		prot_desc->clocks_per_frame);
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	return 0;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
setup_pcm_framing(struct snd_soc_dai * dai,unsigned int rate,struct msp_protdesc * prot_desc)127*4882a593Smuzhiyun static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate,
128*4882a593Smuzhiyun 			struct msp_protdesc *prot_desc)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	u32 frame_length = MSP_FRAME_LEN_1;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	prot_desc->frame_width = 0;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	switch (drvdata->slots) {
137*4882a593Smuzhiyun 	case 1:
138*4882a593Smuzhiyun 		frame_length = MSP_FRAME_LEN_1;
139*4882a593Smuzhiyun 		break;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	case 2:
142*4882a593Smuzhiyun 		frame_length = MSP_FRAME_LEN_2;
143*4882a593Smuzhiyun 		break;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	case 8:
146*4882a593Smuzhiyun 		frame_length = MSP_FRAME_LEN_8;
147*4882a593Smuzhiyun 		break;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	case 16:
150*4882a593Smuzhiyun 		frame_length = MSP_FRAME_LEN_16;
151*4882a593Smuzhiyun 		break;
152*4882a593Smuzhiyun 	default:
153*4882a593Smuzhiyun 		dev_err(dai->dev,
154*4882a593Smuzhiyun 			"%s: Error: Unsupported slot-count (slots = %d)!\n",
155*4882a593Smuzhiyun 			__func__, drvdata->slots);
156*4882a593Smuzhiyun 		return -EINVAL;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	prot_desc->tx_frame_len_1 = frame_length;
160*4882a593Smuzhiyun 	prot_desc->rx_frame_len_1 = frame_length;
161*4882a593Smuzhiyun 	prot_desc->tx_frame_len_2 = frame_length;
162*4882a593Smuzhiyun 	prot_desc->rx_frame_len_2 = frame_length;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;
165*4882a593Smuzhiyun 	prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;
166*4882a593Smuzhiyun 	prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
167*4882a593Smuzhiyun 	prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return setup_frameper(dai, rate, prot_desc);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
setup_clocking(struct snd_soc_dai * dai,unsigned int fmt,struct ux500_msp_config * msp_config)172*4882a593Smuzhiyun static int setup_clocking(struct snd_soc_dai *dai,
173*4882a593Smuzhiyun 			unsigned int fmt,
174*4882a593Smuzhiyun 			struct ux500_msp_config *msp_config)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
177*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
178*4882a593Smuzhiyun 		break;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
181*4882a593Smuzhiyun 		msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT;
182*4882a593Smuzhiyun 		msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 		break;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	default:
187*4882a593Smuzhiyun 		dev_err(dai->dev,
188*4882a593Smuzhiyun 			"%s: Error: Unsupported inversion (fmt = 0x%x)!\n",
189*4882a593Smuzhiyun 			__func__, fmt);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		return -EINVAL;
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
195*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBM_CFM:
196*4882a593Smuzhiyun 		dev_dbg(dai->dev, "%s: Codec is master.\n", __func__);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 		msp_config->iodelay = 0x20;
199*4882a593Smuzhiyun 		msp_config->rx_fsync_sel = 0;
200*4882a593Smuzhiyun 		msp_config->tx_fsync_sel = 1 << TFSSEL_SHIFT;
201*4882a593Smuzhiyun 		msp_config->tx_clk_sel = 0;
202*4882a593Smuzhiyun 		msp_config->rx_clk_sel = 0;
203*4882a593Smuzhiyun 		msp_config->srg_clk_sel = 0x2 << SCKSEL_SHIFT;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 		break;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_CBS_CFS:
208*4882a593Smuzhiyun 		dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 		msp_config->tx_clk_sel = TX_CLK_SEL_SRG;
211*4882a593Smuzhiyun 		msp_config->tx_fsync_sel = TX_SYNC_SRG_PROG;
212*4882a593Smuzhiyun 		msp_config->rx_clk_sel = RX_CLK_SEL_SRG;
213*4882a593Smuzhiyun 		msp_config->rx_fsync_sel = RX_SYNC_SRG;
214*4882a593Smuzhiyun 		msp_config->srg_clk_sel = 1 << SCKSEL_SHIFT;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 		break;
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	default:
219*4882a593Smuzhiyun 		dev_err(dai->dev, "%s: Error: Unsupported master (fmt = 0x%x)!\n",
220*4882a593Smuzhiyun 			__func__, fmt);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 		return -EINVAL;
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	return 0;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
setup_pcm_protdesc(struct snd_soc_dai * dai,unsigned int fmt,struct msp_protdesc * prot_desc)228*4882a593Smuzhiyun static int setup_pcm_protdesc(struct snd_soc_dai *dai,
229*4882a593Smuzhiyun 				unsigned int fmt,
230*4882a593Smuzhiyun 				struct msp_protdesc *prot_desc)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	prot_desc->rx_phase_mode = MSP_SINGLE_PHASE;
233*4882a593Smuzhiyun 	prot_desc->tx_phase_mode = MSP_SINGLE_PHASE;
234*4882a593Smuzhiyun 	prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
235*4882a593Smuzhiyun 	prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
236*4882a593Smuzhiyun 	prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;
237*4882a593Smuzhiyun 	prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;
238*4882a593Smuzhiyun 	prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_HI);
239*4882a593Smuzhiyun 	prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_HI << RFSPOL_SHIFT;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) {
242*4882a593Smuzhiyun 		dev_dbg(dai->dev, "%s: DSP_A.\n", __func__);
243*4882a593Smuzhiyun 		prot_desc->rx_clk_pol = MSP_RISING_EDGE;
244*4882a593Smuzhiyun 		prot_desc->tx_clk_pol = MSP_FALLING_EDGE;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 		prot_desc->rx_data_delay = MSP_DELAY_1;
247*4882a593Smuzhiyun 		prot_desc->tx_data_delay = MSP_DELAY_1;
248*4882a593Smuzhiyun 	} else {
249*4882a593Smuzhiyun 		dev_dbg(dai->dev, "%s: DSP_B.\n", __func__);
250*4882a593Smuzhiyun 		prot_desc->rx_clk_pol = MSP_FALLING_EDGE;
251*4882a593Smuzhiyun 		prot_desc->tx_clk_pol = MSP_RISING_EDGE;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 		prot_desc->rx_data_delay = MSP_DELAY_0;
254*4882a593Smuzhiyun 		prot_desc->tx_data_delay = MSP_DELAY_0;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	prot_desc->rx_half_word_swap = MSP_SWAP_NONE;
258*4882a593Smuzhiyun 	prot_desc->tx_half_word_swap = MSP_SWAP_NONE;
259*4882a593Smuzhiyun 	prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
260*4882a593Smuzhiyun 	prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
261*4882a593Smuzhiyun 	prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	return 0;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
setup_i2s_protdesc(struct msp_protdesc * prot_desc)266*4882a593Smuzhiyun static int setup_i2s_protdesc(struct msp_protdesc *prot_desc)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	prot_desc->rx_phase_mode = MSP_DUAL_PHASE;
269*4882a593Smuzhiyun 	prot_desc->tx_phase_mode = MSP_DUAL_PHASE;
270*4882a593Smuzhiyun 	prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;
271*4882a593Smuzhiyun 	prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;
272*4882a593Smuzhiyun 	prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;
273*4882a593Smuzhiyun 	prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;
274*4882a593Smuzhiyun 	prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_LO);
275*4882a593Smuzhiyun 	prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_LO << RFSPOL_SHIFT;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	prot_desc->rx_frame_len_1 = MSP_FRAME_LEN_1;
278*4882a593Smuzhiyun 	prot_desc->rx_frame_len_2 = MSP_FRAME_LEN_1;
279*4882a593Smuzhiyun 	prot_desc->tx_frame_len_1 = MSP_FRAME_LEN_1;
280*4882a593Smuzhiyun 	prot_desc->tx_frame_len_2 = MSP_FRAME_LEN_1;
281*4882a593Smuzhiyun 	prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;
282*4882a593Smuzhiyun 	prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
283*4882a593Smuzhiyun 	prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;
284*4882a593Smuzhiyun 	prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	prot_desc->rx_clk_pol = MSP_RISING_EDGE;
287*4882a593Smuzhiyun 	prot_desc->tx_clk_pol = MSP_FALLING_EDGE;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	prot_desc->rx_data_delay = MSP_DELAY_0;
290*4882a593Smuzhiyun 	prot_desc->tx_data_delay = MSP_DELAY_0;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	prot_desc->tx_half_word_swap = MSP_SWAP_NONE;
293*4882a593Smuzhiyun 	prot_desc->rx_half_word_swap = MSP_SWAP_NONE;
294*4882a593Smuzhiyun 	prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
295*4882a593Smuzhiyun 	prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
296*4882a593Smuzhiyun 	prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	return 0;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
setup_msp_config(struct snd_pcm_substream * substream,struct snd_soc_dai * dai,struct ux500_msp_config * msp_config)301*4882a593Smuzhiyun static int setup_msp_config(struct snd_pcm_substream *substream,
302*4882a593Smuzhiyun 			struct snd_soc_dai *dai,
303*4882a593Smuzhiyun 			struct ux500_msp_config *msp_config)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
306*4882a593Smuzhiyun 	struct msp_protdesc *prot_desc = &msp_config->protdesc;
307*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
308*4882a593Smuzhiyun 	unsigned int fmt = drvdata->fmt;
309*4882a593Smuzhiyun 	int ret;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	memset(msp_config, 0, sizeof(*msp_config));
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	msp_config->f_inputclk = drvdata->master_clk;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	msp_config->tx_fifo_config = TX_FIFO_ENABLE;
316*4882a593Smuzhiyun 	msp_config->rx_fifo_config = RX_FIFO_ENABLE;
317*4882a593Smuzhiyun 	msp_config->def_elem_len = 1;
318*4882a593Smuzhiyun 	msp_config->direction = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
319*4882a593Smuzhiyun 				MSP_DIR_TX : MSP_DIR_RX;
320*4882a593Smuzhiyun 	msp_config->data_size = MSP_DATA_BITS_32;
321*4882a593Smuzhiyun 	msp_config->frame_freq = runtime->rate;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: f_inputclk = %u, frame_freq = %u.\n",
324*4882a593Smuzhiyun 	       __func__, msp_config->f_inputclk, msp_config->frame_freq);
325*4882a593Smuzhiyun 	/* To avoid division by zero */
326*4882a593Smuzhiyun 	prot_desc->clocks_per_frame = 1;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__,
329*4882a593Smuzhiyun 		runtime->rate, runtime->channels);
330*4882a593Smuzhiyun 	switch (fmt &
331*4882a593Smuzhiyun 		(SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
332*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
333*4882a593Smuzhiyun 		dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 		msp_config->default_protdesc = 1;
336*4882a593Smuzhiyun 		msp_config->protocol = MSP_I2S_PROTOCOL;
337*4882a593Smuzhiyun 		break;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
340*4882a593Smuzhiyun 		dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 		msp_config->data_size = MSP_DATA_BITS_16;
343*4882a593Smuzhiyun 		msp_config->protocol = MSP_I2S_PROTOCOL;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 		ret = setup_i2s_protdesc(prot_desc);
346*4882a593Smuzhiyun 		if (ret < 0)
347*4882a593Smuzhiyun 			return ret;
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 		break;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
352*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
353*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
354*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
355*4882a593Smuzhiyun 		dev_dbg(dai->dev, "%s: PCM format.\n", __func__);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 		msp_config->data_size = MSP_DATA_BITS_16;
358*4882a593Smuzhiyun 		msp_config->protocol = MSP_PCM_PROTOCOL;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 		ret = setup_pcm_protdesc(dai, fmt, prot_desc);
361*4882a593Smuzhiyun 		if (ret < 0)
362*4882a593Smuzhiyun 			return ret;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		ret = setup_pcm_multichan(dai, msp_config);
365*4882a593Smuzhiyun 		if (ret < 0)
366*4882a593Smuzhiyun 			return ret;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 		ret = setup_pcm_framing(dai, runtime->rate, prot_desc);
369*4882a593Smuzhiyun 		if (ret < 0)
370*4882a593Smuzhiyun 			return ret;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 		break;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	default:
375*4882a593Smuzhiyun 		dev_err(dai->dev, "%s: Error: Unsupported format (%d)!\n",
376*4882a593Smuzhiyun 			__func__, fmt);
377*4882a593Smuzhiyun 		return -EINVAL;
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	return setup_clocking(dai, fmt, msp_config);
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
ux500_msp_dai_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)383*4882a593Smuzhiyun static int ux500_msp_dai_startup(struct snd_pcm_substream *substream,
384*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	int ret = 0;
387*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
390*4882a593Smuzhiyun 		snd_pcm_stream_str(substream));
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	/* Enable regulator */
393*4882a593Smuzhiyun 	ret = regulator_enable(drvdata->reg_vape);
394*4882a593Smuzhiyun 	if (ret != 0) {
395*4882a593Smuzhiyun 		dev_err(drvdata->msp->dev,
396*4882a593Smuzhiyun 			"%s: Failed to enable regulator!\n", __func__);
397*4882a593Smuzhiyun 		return ret;
398*4882a593Smuzhiyun 	}
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	/* Prepare and enable clocks */
401*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: Enabling MSP-clocks.\n", __func__);
402*4882a593Smuzhiyun 	ret = clk_prepare_enable(drvdata->pclk);
403*4882a593Smuzhiyun 	if (ret) {
404*4882a593Smuzhiyun 		dev_err(drvdata->msp->dev,
405*4882a593Smuzhiyun 			"%s: Failed to prepare/enable pclk!\n", __func__);
406*4882a593Smuzhiyun 		goto err_pclk;
407*4882a593Smuzhiyun 	}
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	ret = clk_prepare_enable(drvdata->clk);
410*4882a593Smuzhiyun 	if (ret) {
411*4882a593Smuzhiyun 		dev_err(drvdata->msp->dev,
412*4882a593Smuzhiyun 			"%s: Failed to prepare/enable clk!\n", __func__);
413*4882a593Smuzhiyun 		goto err_clk;
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	return ret;
417*4882a593Smuzhiyun err_clk:
418*4882a593Smuzhiyun 	clk_disable_unprepare(drvdata->pclk);
419*4882a593Smuzhiyun err_pclk:
420*4882a593Smuzhiyun 	regulator_disable(drvdata->reg_vape);
421*4882a593Smuzhiyun 	return ret;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun 
ux500_msp_dai_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)424*4882a593Smuzhiyun static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
425*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	int ret;
428*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
429*4882a593Smuzhiyun 	bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
432*4882a593Smuzhiyun 		snd_pcm_stream_str(substream));
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	if (drvdata->vape_opp_constraint == 1) {
435*4882a593Smuzhiyun 		prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
436*4882a593Smuzhiyun 					"ux500_msp_i2s", 50);
437*4882a593Smuzhiyun 		drvdata->vape_opp_constraint = 0;
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	if (ux500_msp_i2s_close(drvdata->msp,
441*4882a593Smuzhiyun 				is_playback ? MSP_DIR_TX : MSP_DIR_RX)) {
442*4882a593Smuzhiyun 		dev_err(dai->dev,
443*4882a593Smuzhiyun 			"%s: Error: MSP %d (%s): Unable to close i2s.\n",
444*4882a593Smuzhiyun 			__func__, dai->id, snd_pcm_stream_str(substream));
445*4882a593Smuzhiyun 	}
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	/* Disable and unprepare clocks */
448*4882a593Smuzhiyun 	clk_disable_unprepare(drvdata->clk);
449*4882a593Smuzhiyun 	clk_disable_unprepare(drvdata->pclk);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	/* Disable regulator */
452*4882a593Smuzhiyun 	ret = regulator_disable(drvdata->reg_vape);
453*4882a593Smuzhiyun 	if (ret < 0)
454*4882a593Smuzhiyun 		dev_err(dai->dev,
455*4882a593Smuzhiyun 			"%s: ERROR: Failed to disable regulator (%d)!\n",
456*4882a593Smuzhiyun 			__func__, ret);
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
ux500_msp_dai_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)459*4882a593Smuzhiyun static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
460*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun 	int ret = 0;
463*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
464*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
465*4882a593Smuzhiyun 	struct ux500_msp_config msp_config;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (rate = %d).\n", __func__,
468*4882a593Smuzhiyun 		dai->id, snd_pcm_stream_str(substream), runtime->rate);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	setup_msp_config(substream, dai, &msp_config);
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	ret = ux500_msp_i2s_open(drvdata->msp, &msp_config);
473*4882a593Smuzhiyun 	if (ret < 0) {
474*4882a593Smuzhiyun 		dev_err(dai->dev, "%s: Error: msp_setup failed (ret = %d)!\n",
475*4882a593Smuzhiyun 			__func__, ret);
476*4882a593Smuzhiyun 		return ret;
477*4882a593Smuzhiyun 	}
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	/* Set OPP-level */
480*4882a593Smuzhiyun 	if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) &&
481*4882a593Smuzhiyun 		(drvdata->msp->f_bitclk > 19200000)) {
482*4882a593Smuzhiyun 		/* If the bit-clock is higher than 19.2MHz, Vape should be
483*4882a593Smuzhiyun 		 * run in 100% OPP. Only when bit-clock is used (MSP master)
484*4882a593Smuzhiyun 		 */
485*4882a593Smuzhiyun 		prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
486*4882a593Smuzhiyun 					"ux500-msp-i2s", 100);
487*4882a593Smuzhiyun 		drvdata->vape_opp_constraint = 1;
488*4882a593Smuzhiyun 	} else {
489*4882a593Smuzhiyun 		prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
490*4882a593Smuzhiyun 					"ux500-msp-i2s", 50);
491*4882a593Smuzhiyun 		drvdata->vape_opp_constraint = 0;
492*4882a593Smuzhiyun 	}
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	return ret;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun 
ux500_msp_dai_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)497*4882a593Smuzhiyun static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
498*4882a593Smuzhiyun 				struct snd_pcm_hw_params *params,
499*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun 	unsigned int mask, slots_active;
502*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
503*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n",
506*4882a593Smuzhiyun 			__func__, dai->id, snd_pcm_stream_str(substream));
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
509*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S:
510*4882a593Smuzhiyun 		snd_pcm_hw_constraint_minmax(runtime,
511*4882a593Smuzhiyun 				SNDRV_PCM_HW_PARAM_CHANNELS,
512*4882a593Smuzhiyun 				1, 2);
513*4882a593Smuzhiyun 		break;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B:
516*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A:
517*4882a593Smuzhiyun 		mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
518*4882a593Smuzhiyun 			drvdata->tx_mask :
519*4882a593Smuzhiyun 			drvdata->rx_mask;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 		slots_active = hweight32(mask);
522*4882a593Smuzhiyun 		dev_dbg(dai->dev, "TDM-slots active: %d", slots_active);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 		snd_pcm_hw_constraint_single(runtime,
525*4882a593Smuzhiyun 				SNDRV_PCM_HW_PARAM_CHANNELS,
526*4882a593Smuzhiyun 				slots_active);
527*4882a593Smuzhiyun 		break;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	default:
530*4882a593Smuzhiyun 		dev_err(dai->dev,
531*4882a593Smuzhiyun 			"%s: Error: Unsupported protocol (fmt = 0x%x)!\n",
532*4882a593Smuzhiyun 			__func__, drvdata->fmt);
533*4882a593Smuzhiyun 		return -EINVAL;
534*4882a593Smuzhiyun 	}
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	return 0;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
ux500_msp_dai_set_dai_fmt(struct snd_soc_dai * dai,unsigned int fmt)539*4882a593Smuzhiyun static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai,
540*4882a593Smuzhiyun 				unsigned int fmt)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
547*4882a593Smuzhiyun 		SND_SOC_DAIFMT_MASTER_MASK)) {
548*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
549*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
550*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
551*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
552*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
553*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
554*4882a593Smuzhiyun 		break;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	default:
557*4882a593Smuzhiyun 		dev_err(dai->dev,
558*4882a593Smuzhiyun 			"%s: Error: Unsupported protocol/master (fmt = 0x%x)!\n",
559*4882a593Smuzhiyun 			__func__, drvdata->fmt);
560*4882a593Smuzhiyun 		return -EINVAL;
561*4882a593Smuzhiyun 	}
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
564*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_NF:
565*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_NB_IF:
566*4882a593Smuzhiyun 	case SND_SOC_DAIFMT_IB_IF:
567*4882a593Smuzhiyun 		break;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	default:
570*4882a593Smuzhiyun 		dev_err(dai->dev,
571*4882a593Smuzhiyun 			"%s: Error: Unsupported inversion (fmt = 0x%x)!\n",
572*4882a593Smuzhiyun 			__func__, drvdata->fmt);
573*4882a593Smuzhiyun 		return -EINVAL;
574*4882a593Smuzhiyun 	}
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	drvdata->fmt = fmt;
577*4882a593Smuzhiyun 	return 0;
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun 
ux500_msp_dai_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)580*4882a593Smuzhiyun static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai,
581*4882a593Smuzhiyun 				unsigned int tx_mask,
582*4882a593Smuzhiyun 				unsigned int rx_mask,
583*4882a593Smuzhiyun 				int slots, int slot_width)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
586*4882a593Smuzhiyun 	unsigned int cap;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	switch (slots) {
589*4882a593Smuzhiyun 	case 1:
590*4882a593Smuzhiyun 		cap = 0x01;
591*4882a593Smuzhiyun 		break;
592*4882a593Smuzhiyun 	case 2:
593*4882a593Smuzhiyun 		cap = 0x03;
594*4882a593Smuzhiyun 		break;
595*4882a593Smuzhiyun 	case 8:
596*4882a593Smuzhiyun 		cap = 0xFF;
597*4882a593Smuzhiyun 		break;
598*4882a593Smuzhiyun 	case 16:
599*4882a593Smuzhiyun 		cap = 0xFFFF;
600*4882a593Smuzhiyun 		break;
601*4882a593Smuzhiyun 	default:
602*4882a593Smuzhiyun 		dev_err(dai->dev, "%s: Error: Unsupported slot-count (%d)!\n",
603*4882a593Smuzhiyun 			__func__, slots);
604*4882a593Smuzhiyun 		return -EINVAL;
605*4882a593Smuzhiyun 	}
606*4882a593Smuzhiyun 	drvdata->slots = slots;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	if (!(slot_width == 16)) {
609*4882a593Smuzhiyun 		dev_err(dai->dev, "%s: Error: Unsupported slot-width (%d)!\n",
610*4882a593Smuzhiyun 			__func__, slot_width);
611*4882a593Smuzhiyun 		return -EINVAL;
612*4882a593Smuzhiyun 	}
613*4882a593Smuzhiyun 	drvdata->slot_width = slot_width;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	drvdata->tx_mask = tx_mask & cap;
616*4882a593Smuzhiyun 	drvdata->rx_mask = rx_mask & cap;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	return 0;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun 
ux500_msp_dai_set_dai_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)621*4882a593Smuzhiyun static int ux500_msp_dai_set_dai_sysclk(struct snd_soc_dai *dai,
622*4882a593Smuzhiyun 					int clk_id, unsigned int freq, int dir)
623*4882a593Smuzhiyun {
624*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: MSP %d: Enter. clk-id: %d, freq: %u.\n",
627*4882a593Smuzhiyun 		__func__, dai->id, clk_id, freq);
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	switch (clk_id) {
630*4882a593Smuzhiyun 	case UX500_MSP_MASTER_CLOCK:
631*4882a593Smuzhiyun 		drvdata->master_clk = freq;
632*4882a593Smuzhiyun 		break;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	default:
635*4882a593Smuzhiyun 		dev_err(dai->dev, "%s: MSP %d: Invalid clk-id (%d)!\n",
636*4882a593Smuzhiyun 			__func__, dai->id, clk_id);
637*4882a593Smuzhiyun 		return -EINVAL;
638*4882a593Smuzhiyun 	}
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	return 0;
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun 
ux500_msp_dai_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)643*4882a593Smuzhiyun static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,
644*4882a593Smuzhiyun 				int cmd, struct snd_soc_dai *dai)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun 	int ret = 0;
647*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (msp->id = %d, cmd = %d).\n",
650*4882a593Smuzhiyun 		__func__, dai->id, snd_pcm_stream_str(substream),
651*4882a593Smuzhiyun 		(int)drvdata->msp->id, cmd);
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	ret = ux500_msp_i2s_trigger(drvdata->msp, cmd, substream->stream);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	return ret;
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun 
ux500_msp_dai_of_probe(struct snd_soc_dai * dai)658*4882a593Smuzhiyun static int ux500_msp_dai_of_probe(struct snd_soc_dai *dai)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
661*4882a593Smuzhiyun 	struct snd_dmaengine_dai_dma_data *playback_dma_data;
662*4882a593Smuzhiyun 	struct snd_dmaengine_dai_dma_data *capture_dma_data;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	playback_dma_data = devm_kzalloc(dai->dev,
665*4882a593Smuzhiyun 					 sizeof(*playback_dma_data),
666*4882a593Smuzhiyun 					 GFP_KERNEL);
667*4882a593Smuzhiyun 	if (!playback_dma_data)
668*4882a593Smuzhiyun 		return -ENOMEM;
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	capture_dma_data = devm_kzalloc(dai->dev,
671*4882a593Smuzhiyun 					sizeof(*capture_dma_data),
672*4882a593Smuzhiyun 					GFP_KERNEL);
673*4882a593Smuzhiyun 	if (!capture_dma_data)
674*4882a593Smuzhiyun 		return -ENOMEM;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	playback_dma_data->addr = drvdata->msp->playback_dma_data.tx_rx_addr;
677*4882a593Smuzhiyun 	capture_dma_data->addr = drvdata->msp->capture_dma_data.tx_rx_addr;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	playback_dma_data->maxburst = 4;
680*4882a593Smuzhiyun 	capture_dma_data->maxburst = 4;
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	snd_soc_dai_init_dma_data(dai, playback_dma_data, capture_dma_data);
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	return 0;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun 
ux500_msp_dai_probe(struct snd_soc_dai * dai)687*4882a593Smuzhiyun static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
688*4882a593Smuzhiyun {
689*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
690*4882a593Smuzhiyun 	struct msp_i2s_platform_data *pdata = dai->dev->platform_data;
691*4882a593Smuzhiyun 	int ret;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	if (!pdata) {
694*4882a593Smuzhiyun 		ret = ux500_msp_dai_of_probe(dai);
695*4882a593Smuzhiyun 		return ret;
696*4882a593Smuzhiyun 	}
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	drvdata->msp->playback_dma_data.data_size = drvdata->slot_width;
699*4882a593Smuzhiyun 	drvdata->msp->capture_dma_data.data_size = drvdata->slot_width;
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	snd_soc_dai_init_dma_data(dai,
702*4882a593Smuzhiyun 				  &drvdata->msp->playback_dma_data,
703*4882a593Smuzhiyun 				  &drvdata->msp->capture_dma_data);
704*4882a593Smuzhiyun 	return 0;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun static const struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
708*4882a593Smuzhiyun 	{
709*4882a593Smuzhiyun 		.set_sysclk = ux500_msp_dai_set_dai_sysclk,
710*4882a593Smuzhiyun 		.set_fmt = ux500_msp_dai_set_dai_fmt,
711*4882a593Smuzhiyun 		.set_tdm_slot = ux500_msp_dai_set_tdm_slot,
712*4882a593Smuzhiyun 		.startup = ux500_msp_dai_startup,
713*4882a593Smuzhiyun 		.shutdown = ux500_msp_dai_shutdown,
714*4882a593Smuzhiyun 		.prepare = ux500_msp_dai_prepare,
715*4882a593Smuzhiyun 		.trigger = ux500_msp_dai_trigger,
716*4882a593Smuzhiyun 		.hw_params = ux500_msp_dai_hw_params,
717*4882a593Smuzhiyun 	}
718*4882a593Smuzhiyun };
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun static struct snd_soc_dai_driver ux500_msp_dai_drv = {
721*4882a593Smuzhiyun 	.probe                 = ux500_msp_dai_probe,
722*4882a593Smuzhiyun 	.playback.channels_min = UX500_MSP_MIN_CHANNELS,
723*4882a593Smuzhiyun 	.playback.channels_max = UX500_MSP_MAX_CHANNELS,
724*4882a593Smuzhiyun 	.playback.rates        = UX500_I2S_RATES,
725*4882a593Smuzhiyun 	.playback.formats      = UX500_I2S_FORMATS,
726*4882a593Smuzhiyun 	.capture.channels_min  = UX500_MSP_MIN_CHANNELS,
727*4882a593Smuzhiyun 	.capture.channels_max  = UX500_MSP_MAX_CHANNELS,
728*4882a593Smuzhiyun 	.capture.rates         = UX500_I2S_RATES,
729*4882a593Smuzhiyun 	.capture.formats       = UX500_I2S_FORMATS,
730*4882a593Smuzhiyun 	.ops                   = ux500_msp_dai_ops,
731*4882a593Smuzhiyun };
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun static const struct snd_soc_component_driver ux500_msp_component = {
734*4882a593Smuzhiyun 	.name		= "ux500-msp",
735*4882a593Smuzhiyun };
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 
ux500_msp_drv_probe(struct platform_device * pdev)738*4882a593Smuzhiyun static int ux500_msp_drv_probe(struct platform_device *pdev)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata;
741*4882a593Smuzhiyun 	struct msp_i2s_platform_data *pdata = pdev->dev.platform_data;
742*4882a593Smuzhiyun 	struct device_node *np = pdev->dev.of_node;
743*4882a593Smuzhiyun 	int ret = 0;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	if (!pdata && !np) {
746*4882a593Smuzhiyun 		dev_err(&pdev->dev, "No platform data or Device Tree found\n");
747*4882a593Smuzhiyun 		return -ENODEV;
748*4882a593Smuzhiyun 	}
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	drvdata = devm_kzalloc(&pdev->dev,
751*4882a593Smuzhiyun 				sizeof(struct ux500_msp_i2s_drvdata),
752*4882a593Smuzhiyun 				GFP_KERNEL);
753*4882a593Smuzhiyun 	if (!drvdata)
754*4882a593Smuzhiyun 		return -ENOMEM;
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	drvdata->fmt = 0;
757*4882a593Smuzhiyun 	drvdata->slots = 1;
758*4882a593Smuzhiyun 	drvdata->tx_mask = 0x01;
759*4882a593Smuzhiyun 	drvdata->rx_mask = 0x01;
760*4882a593Smuzhiyun 	drvdata->slot_width = 16;
761*4882a593Smuzhiyun 	drvdata->master_clk = MSP_INPUT_FREQ_APB;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape");
764*4882a593Smuzhiyun 	if (IS_ERR(drvdata->reg_vape)) {
765*4882a593Smuzhiyun 		ret = (int)PTR_ERR(drvdata->reg_vape);
766*4882a593Smuzhiyun 		dev_err(&pdev->dev,
767*4882a593Smuzhiyun 			"%s: ERROR: Failed to get Vape supply (%d)!\n",
768*4882a593Smuzhiyun 			__func__, ret);
769*4882a593Smuzhiyun 		return ret;
770*4882a593Smuzhiyun 	}
771*4882a593Smuzhiyun 	prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
774*4882a593Smuzhiyun 	if (IS_ERR(drvdata->pclk)) {
775*4882a593Smuzhiyun 		ret = (int)PTR_ERR(drvdata->pclk);
776*4882a593Smuzhiyun 		dev_err(&pdev->dev,
777*4882a593Smuzhiyun 			"%s: ERROR: devm_clk_get of pclk failed (%d)!\n",
778*4882a593Smuzhiyun 			__func__, ret);
779*4882a593Smuzhiyun 		return ret;
780*4882a593Smuzhiyun 	}
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	drvdata->clk = devm_clk_get(&pdev->dev, NULL);
783*4882a593Smuzhiyun 	if (IS_ERR(drvdata->clk)) {
784*4882a593Smuzhiyun 		ret = (int)PTR_ERR(drvdata->clk);
785*4882a593Smuzhiyun 		dev_err(&pdev->dev,
786*4882a593Smuzhiyun 			"%s: ERROR: devm_clk_get failed (%d)!\n",
787*4882a593Smuzhiyun 			__func__, ret);
788*4882a593Smuzhiyun 		return ret;
789*4882a593Smuzhiyun 	}
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp,
792*4882a593Smuzhiyun 				pdev->dev.platform_data);
793*4882a593Smuzhiyun 	if (!drvdata->msp) {
794*4882a593Smuzhiyun 		dev_err(&pdev->dev,
795*4882a593Smuzhiyun 			"%s: ERROR: Failed to init MSP-struct (%d)!",
796*4882a593Smuzhiyun 			__func__, ret);
797*4882a593Smuzhiyun 		return ret;
798*4882a593Smuzhiyun 	}
799*4882a593Smuzhiyun 	dev_set_drvdata(&pdev->dev, drvdata);
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component,
802*4882a593Smuzhiyun 					 &ux500_msp_dai_drv, 1);
803*4882a593Smuzhiyun 	if (ret < 0) {
804*4882a593Smuzhiyun 		dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
805*4882a593Smuzhiyun 			__func__, drvdata->msp->id);
806*4882a593Smuzhiyun 		return ret;
807*4882a593Smuzhiyun 	}
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	ret = ux500_pcm_register_platform(pdev);
810*4882a593Smuzhiyun 	if (ret < 0) {
811*4882a593Smuzhiyun 		dev_err(&pdev->dev,
812*4882a593Smuzhiyun 			"Error: %s: Failed to register PCM platform device!\n",
813*4882a593Smuzhiyun 			__func__);
814*4882a593Smuzhiyun 		goto err_reg_plat;
815*4882a593Smuzhiyun 	}
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	return 0;
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun err_reg_plat:
820*4882a593Smuzhiyun 	snd_soc_unregister_component(&pdev->dev);
821*4882a593Smuzhiyun 	return ret;
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun 
ux500_msp_drv_remove(struct platform_device * pdev)824*4882a593Smuzhiyun static int ux500_msp_drv_remove(struct platform_device *pdev)
825*4882a593Smuzhiyun {
826*4882a593Smuzhiyun 	struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	ux500_pcm_unregister_platform(pdev);
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	snd_soc_unregister_component(&pdev->dev);
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp);
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 	return 0;
837*4882a593Smuzhiyun }
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun static const struct of_device_id ux500_msp_i2s_match[] = {
840*4882a593Smuzhiyun 	{ .compatible = "stericsson,ux500-msp-i2s", },
841*4882a593Smuzhiyun 	{},
842*4882a593Smuzhiyun };
843*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, ux500_msp_i2s_match);
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun static struct platform_driver msp_i2s_driver = {
846*4882a593Smuzhiyun 	.driver = {
847*4882a593Smuzhiyun 		.name = "ux500-msp-i2s",
848*4882a593Smuzhiyun 		.of_match_table = ux500_msp_i2s_match,
849*4882a593Smuzhiyun 	},
850*4882a593Smuzhiyun 	.probe = ux500_msp_drv_probe,
851*4882a593Smuzhiyun 	.remove = ux500_msp_drv_remove,
852*4882a593Smuzhiyun };
853*4882a593Smuzhiyun module_platform_driver(msp_i2s_driver);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
856