xref: /linux/sound/soc/ux500/ux500_msp_i2s.c (revision 3592b7f6)
1*3592b7f6SOla Lilja /*
2*3592b7f6SOla Lilja  * Copyright (C) ST-Ericsson SA 2012
3*3592b7f6SOla Lilja  *
4*3592b7f6SOla Lilja  * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
5*3592b7f6SOla Lilja  *         Roger Nilsson <roger.xr.nilsson@stericsson.com>,
6*3592b7f6SOla Lilja  *         Sandeep Kaushik <sandeep.kaushik@st.com>
7*3592b7f6SOla Lilja  *         for ST-Ericsson.
8*3592b7f6SOla Lilja  *
9*3592b7f6SOla Lilja  * License terms:
10*3592b7f6SOla Lilja  *
11*3592b7f6SOla Lilja  * This program is free software; you can redistribute it and/or modify
12*3592b7f6SOla Lilja  * it under the terms of the GNU General Public License version 2 as published
13*3592b7f6SOla Lilja  * by the Free Software Foundation.
14*3592b7f6SOla Lilja  */
15*3592b7f6SOla Lilja 
16*3592b7f6SOla Lilja #include <linux/module.h>
17*3592b7f6SOla Lilja #include <linux/platform_device.h>
18*3592b7f6SOla Lilja #include <linux/delay.h>
19*3592b7f6SOla Lilja #include <linux/slab.h>
20*3592b7f6SOla Lilja 
21*3592b7f6SOla Lilja #include <mach/hardware.h>
22*3592b7f6SOla Lilja #include <mach/board-mop500-msp.h>
23*3592b7f6SOla Lilja 
24*3592b7f6SOla Lilja #include <sound/soc.h>
25*3592b7f6SOla Lilja 
26*3592b7f6SOla Lilja #include "ux500_msp_i2s.h"
27*3592b7f6SOla Lilja 
28*3592b7f6SOla Lilja  /* Protocol desciptors */
29*3592b7f6SOla Lilja static const struct msp_protdesc prot_descs[] = {
30*3592b7f6SOla Lilja 	{ /* I2S */
31*3592b7f6SOla Lilja 		MSP_SINGLE_PHASE,
32*3592b7f6SOla Lilja 		MSP_SINGLE_PHASE,
33*3592b7f6SOla Lilja 		MSP_PHASE2_START_MODE_IMEDIATE,
34*3592b7f6SOla Lilja 		MSP_PHASE2_START_MODE_IMEDIATE,
35*3592b7f6SOla Lilja 		MSP_BTF_MS_BIT_FIRST,
36*3592b7f6SOla Lilja 		MSP_BTF_MS_BIT_FIRST,
37*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
38*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
39*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
40*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
41*3592b7f6SOla Lilja 		MSP_ELEM_LEN_32,
42*3592b7f6SOla Lilja 		MSP_ELEM_LEN_32,
43*3592b7f6SOla Lilja 		MSP_ELEM_LEN_32,
44*3592b7f6SOla Lilja 		MSP_ELEM_LEN_32,
45*3592b7f6SOla Lilja 		MSP_DELAY_1,
46*3592b7f6SOla Lilja 		MSP_DELAY_1,
47*3592b7f6SOla Lilja 		MSP_RISING_EDGE,
48*3592b7f6SOla Lilja 		MSP_FALLING_EDGE,
49*3592b7f6SOla Lilja 		MSP_FSYNC_POL_ACT_LO,
50*3592b7f6SOla Lilja 		MSP_FSYNC_POL_ACT_LO,
51*3592b7f6SOla Lilja 		MSP_SWAP_NONE,
52*3592b7f6SOla Lilja 		MSP_SWAP_NONE,
53*3592b7f6SOla Lilja 		MSP_COMPRESS_MODE_LINEAR,
54*3592b7f6SOla Lilja 		MSP_EXPAND_MODE_LINEAR,
55*3592b7f6SOla Lilja 		MSP_FSYNC_IGNORE,
56*3592b7f6SOla Lilja 		31,
57*3592b7f6SOla Lilja 		15,
58*3592b7f6SOla Lilja 		32,
59*3592b7f6SOla Lilja 	}, { /* PCM */
60*3592b7f6SOla Lilja 		MSP_DUAL_PHASE,
61*3592b7f6SOla Lilja 		MSP_DUAL_PHASE,
62*3592b7f6SOla Lilja 		MSP_PHASE2_START_MODE_FSYNC,
63*3592b7f6SOla Lilja 		MSP_PHASE2_START_MODE_FSYNC,
64*3592b7f6SOla Lilja 		MSP_BTF_MS_BIT_FIRST,
65*3592b7f6SOla Lilja 		MSP_BTF_MS_BIT_FIRST,
66*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
67*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
68*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
69*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
70*3592b7f6SOla Lilja 		MSP_ELEM_LEN_16,
71*3592b7f6SOla Lilja 		MSP_ELEM_LEN_16,
72*3592b7f6SOla Lilja 		MSP_ELEM_LEN_16,
73*3592b7f6SOla Lilja 		MSP_ELEM_LEN_16,
74*3592b7f6SOla Lilja 		MSP_DELAY_0,
75*3592b7f6SOla Lilja 		MSP_DELAY_0,
76*3592b7f6SOla Lilja 		MSP_RISING_EDGE,
77*3592b7f6SOla Lilja 		MSP_FALLING_EDGE,
78*3592b7f6SOla Lilja 		MSP_FSYNC_POL_ACT_HI,
79*3592b7f6SOla Lilja 		MSP_FSYNC_POL_ACT_HI,
80*3592b7f6SOla Lilja 		MSP_SWAP_NONE,
81*3592b7f6SOla Lilja 		MSP_SWAP_NONE,
82*3592b7f6SOla Lilja 		MSP_COMPRESS_MODE_LINEAR,
83*3592b7f6SOla Lilja 		MSP_EXPAND_MODE_LINEAR,
84*3592b7f6SOla Lilja 		MSP_FSYNC_IGNORE,
85*3592b7f6SOla Lilja 		255,
86*3592b7f6SOla Lilja 		0,
87*3592b7f6SOla Lilja 		256,
88*3592b7f6SOla Lilja 	}, { /* Companded PCM */
89*3592b7f6SOla Lilja 		MSP_SINGLE_PHASE,
90*3592b7f6SOla Lilja 		MSP_SINGLE_PHASE,
91*3592b7f6SOla Lilja 		MSP_PHASE2_START_MODE_FSYNC,
92*3592b7f6SOla Lilja 		MSP_PHASE2_START_MODE_FSYNC,
93*3592b7f6SOla Lilja 		MSP_BTF_MS_BIT_FIRST,
94*3592b7f6SOla Lilja 		MSP_BTF_MS_BIT_FIRST,
95*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
96*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
97*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
98*3592b7f6SOla Lilja 		MSP_FRAME_LEN_1,
99*3592b7f6SOla Lilja 		MSP_ELEM_LEN_8,
100*3592b7f6SOla Lilja 		MSP_ELEM_LEN_8,
101*3592b7f6SOla Lilja 		MSP_ELEM_LEN_8,
102*3592b7f6SOla Lilja 		MSP_ELEM_LEN_8,
103*3592b7f6SOla Lilja 		MSP_DELAY_0,
104*3592b7f6SOla Lilja 		MSP_DELAY_0,
105*3592b7f6SOla Lilja 		MSP_RISING_EDGE,
106*3592b7f6SOla Lilja 		MSP_RISING_EDGE,
107*3592b7f6SOla Lilja 		MSP_FSYNC_POL_ACT_HI,
108*3592b7f6SOla Lilja 		MSP_FSYNC_POL_ACT_HI,
109*3592b7f6SOla Lilja 		MSP_SWAP_NONE,
110*3592b7f6SOla Lilja 		MSP_SWAP_NONE,
111*3592b7f6SOla Lilja 		MSP_COMPRESS_MODE_LINEAR,
112*3592b7f6SOla Lilja 		MSP_EXPAND_MODE_LINEAR,
113*3592b7f6SOla Lilja 		MSP_FSYNC_IGNORE,
114*3592b7f6SOla Lilja 		255,
115*3592b7f6SOla Lilja 		0,
116*3592b7f6SOla Lilja 		256,
117*3592b7f6SOla Lilja 	},
118*3592b7f6SOla Lilja };
119*3592b7f6SOla Lilja 
120*3592b7f6SOla Lilja static void set_prot_desc_tx(struct ux500_msp *msp,
121*3592b7f6SOla Lilja 			struct msp_protdesc *protdesc,
122*3592b7f6SOla Lilja 			enum msp_data_size data_size)
123*3592b7f6SOla Lilja {
124*3592b7f6SOla Lilja 	u32 temp_reg = 0;
125*3592b7f6SOla Lilja 
126*3592b7f6SOla Lilja 	temp_reg |= MSP_P2_ENABLE_BIT(protdesc->tx_phase_mode);
127*3592b7f6SOla Lilja 	temp_reg |= MSP_P2_START_MODE_BIT(protdesc->tx_phase2_start_mode);
128*3592b7f6SOla Lilja 	temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->tx_frame_len_1);
129*3592b7f6SOla Lilja 	temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->tx_frame_len_2);
130*3592b7f6SOla Lilja 	if (msp->def_elem_len) {
131*3592b7f6SOla Lilja 		temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->tx_elem_len_1);
132*3592b7f6SOla Lilja 		temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->tx_elem_len_2);
133*3592b7f6SOla Lilja 	} else {
134*3592b7f6SOla Lilja 		temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
135*3592b7f6SOla Lilja 		temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
136*3592b7f6SOla Lilja 	}
137*3592b7f6SOla Lilja 	temp_reg |= MSP_DATA_DELAY_BITS(protdesc->tx_data_delay);
138*3592b7f6SOla Lilja 	temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->tx_byte_order);
139*3592b7f6SOla Lilja 	temp_reg |= MSP_FSYNC_POL(protdesc->tx_fsync_pol);
140*3592b7f6SOla Lilja 	temp_reg |= MSP_DATA_WORD_SWAP(protdesc->tx_half_word_swap);
141*3592b7f6SOla Lilja 	temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->compression_mode);
142*3592b7f6SOla Lilja 	temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);
143*3592b7f6SOla Lilja 
144*3592b7f6SOla Lilja 	writel(temp_reg, msp->registers + MSP_TCF);
145*3592b7f6SOla Lilja }
146*3592b7f6SOla Lilja 
147*3592b7f6SOla Lilja static void set_prot_desc_rx(struct ux500_msp *msp,
148*3592b7f6SOla Lilja 			struct msp_protdesc *protdesc,
149*3592b7f6SOla Lilja 			enum msp_data_size data_size)
150*3592b7f6SOla Lilja {
151*3592b7f6SOla Lilja 	u32 temp_reg = 0;
152*3592b7f6SOla Lilja 
153*3592b7f6SOla Lilja 	temp_reg |= MSP_P2_ENABLE_BIT(protdesc->rx_phase_mode);
154*3592b7f6SOla Lilja 	temp_reg |= MSP_P2_START_MODE_BIT(protdesc->rx_phase2_start_mode);
155*3592b7f6SOla Lilja 	temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->rx_frame_len_1);
156*3592b7f6SOla Lilja 	temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->rx_frame_len_2);
157*3592b7f6SOla Lilja 	if (msp->def_elem_len) {
158*3592b7f6SOla Lilja 		temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->rx_elem_len_1);
159*3592b7f6SOla Lilja 		temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->rx_elem_len_2);
160*3592b7f6SOla Lilja 	} else {
161*3592b7f6SOla Lilja 		temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
162*3592b7f6SOla Lilja 		temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
163*3592b7f6SOla Lilja 	}
164*3592b7f6SOla Lilja 
165*3592b7f6SOla Lilja 	temp_reg |= MSP_DATA_DELAY_BITS(protdesc->rx_data_delay);
166*3592b7f6SOla Lilja 	temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->rx_byte_order);
167*3592b7f6SOla Lilja 	temp_reg |= MSP_FSYNC_POL(protdesc->rx_fsync_pol);
168*3592b7f6SOla Lilja 	temp_reg |= MSP_DATA_WORD_SWAP(protdesc->rx_half_word_swap);
169*3592b7f6SOla Lilja 	temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->expansion_mode);
170*3592b7f6SOla Lilja 	temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);
171*3592b7f6SOla Lilja 
172*3592b7f6SOla Lilja 	writel(temp_reg, msp->registers + MSP_RCF);
173*3592b7f6SOla Lilja }
174*3592b7f6SOla Lilja 
175*3592b7f6SOla Lilja static int configure_protocol(struct ux500_msp *msp,
176*3592b7f6SOla Lilja 			struct ux500_msp_config *config)
177*3592b7f6SOla Lilja {
178*3592b7f6SOla Lilja 	struct msp_protdesc *protdesc;
179*3592b7f6SOla Lilja 	enum msp_data_size data_size;
180*3592b7f6SOla Lilja 	u32 temp_reg = 0;
181*3592b7f6SOla Lilja 
182*3592b7f6SOla Lilja 	data_size = config->data_size;
183*3592b7f6SOla Lilja 	msp->def_elem_len = config->def_elem_len;
184*3592b7f6SOla Lilja 	if (config->default_protdesc == 1) {
185*3592b7f6SOla Lilja 		if (config->protocol >= MSP_INVALID_PROTOCOL) {
186*3592b7f6SOla Lilja 			dev_err(msp->dev, "%s: ERROR: Invalid protocol!\n",
187*3592b7f6SOla Lilja 				__func__);
188*3592b7f6SOla Lilja 			return -EINVAL;
189*3592b7f6SOla Lilja 		}
190*3592b7f6SOla Lilja 		protdesc =
191*3592b7f6SOla Lilja 		    (struct msp_protdesc *)&prot_descs[config->protocol];
192*3592b7f6SOla Lilja 	} else {
193*3592b7f6SOla Lilja 		protdesc = (struct msp_protdesc *)&config->protdesc;
194*3592b7f6SOla Lilja 	}
195*3592b7f6SOla Lilja 
196*3592b7f6SOla Lilja 	if (data_size < MSP_DATA_BITS_DEFAULT || data_size > MSP_DATA_BITS_32) {
197*3592b7f6SOla Lilja 		dev_err(msp->dev,
198*3592b7f6SOla Lilja 			"%s: ERROR: Invalid data-size requested (data_size = %d)!\n",
199*3592b7f6SOla Lilja 			__func__, data_size);
200*3592b7f6SOla Lilja 		return -EINVAL;
201*3592b7f6SOla Lilja 	}
202*3592b7f6SOla Lilja 
203*3592b7f6SOla Lilja 	if (config->direction & MSP_DIR_TX)
204*3592b7f6SOla Lilja 		set_prot_desc_tx(msp, protdesc, data_size);
205*3592b7f6SOla Lilja 	if (config->direction & MSP_DIR_RX)
206*3592b7f6SOla Lilja 		set_prot_desc_rx(msp, protdesc, data_size);
207*3592b7f6SOla Lilja 
208*3592b7f6SOla Lilja 	/* The code below should not be separated. */
209*3592b7f6SOla Lilja 	temp_reg = readl(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;
210*3592b7f6SOla Lilja 	temp_reg |= MSP_TX_CLKPOL_BIT(~protdesc->tx_clk_pol);
211*3592b7f6SOla Lilja 	writel(temp_reg, msp->registers + MSP_GCR);
212*3592b7f6SOla Lilja 	temp_reg = readl(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;
213*3592b7f6SOla Lilja 	temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol);
214*3592b7f6SOla Lilja 	writel(temp_reg, msp->registers + MSP_GCR);
215*3592b7f6SOla Lilja 
216*3592b7f6SOla Lilja 	return 0;
217*3592b7f6SOla Lilja }
218*3592b7f6SOla Lilja 
219*3592b7f6SOla Lilja static int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config)
220*3592b7f6SOla Lilja {
221*3592b7f6SOla Lilja 	u32 reg_val_GCR;
222*3592b7f6SOla Lilja 	u32 frame_per = 0;
223*3592b7f6SOla Lilja 	u32 sck_div = 0;
224*3592b7f6SOla Lilja 	u32 frame_width = 0;
225*3592b7f6SOla Lilja 	u32 temp_reg = 0;
226*3592b7f6SOla Lilja 	struct msp_protdesc *protdesc = NULL;
227*3592b7f6SOla Lilja 
228*3592b7f6SOla Lilja 	reg_val_GCR = readl(msp->registers + MSP_GCR);
229*3592b7f6SOla Lilja 	writel(reg_val_GCR & ~SRG_ENABLE, msp->registers + MSP_GCR);
230*3592b7f6SOla Lilja 
231*3592b7f6SOla Lilja 	if (config->default_protdesc)
232*3592b7f6SOla Lilja 		protdesc =
233*3592b7f6SOla Lilja 			(struct msp_protdesc *)&prot_descs[config->protocol];
234*3592b7f6SOla Lilja 	else
235*3592b7f6SOla Lilja 		protdesc = (struct msp_protdesc *)&config->protdesc;
236*3592b7f6SOla Lilja 
237*3592b7f6SOla Lilja 	switch (config->protocol) {
238*3592b7f6SOla Lilja 	case MSP_PCM_PROTOCOL:
239*3592b7f6SOla Lilja 	case MSP_PCM_COMPAND_PROTOCOL:
240*3592b7f6SOla Lilja 		frame_width = protdesc->frame_width;
241*3592b7f6SOla Lilja 		sck_div = config->f_inputclk / (config->frame_freq *
242*3592b7f6SOla Lilja 			(protdesc->clocks_per_frame));
243*3592b7f6SOla Lilja 		frame_per = protdesc->frame_period;
244*3592b7f6SOla Lilja 		break;
245*3592b7f6SOla Lilja 	case MSP_I2S_PROTOCOL:
246*3592b7f6SOla Lilja 		frame_width = protdesc->frame_width;
247*3592b7f6SOla Lilja 		sck_div = config->f_inputclk / (config->frame_freq *
248*3592b7f6SOla Lilja 			(protdesc->clocks_per_frame));
249*3592b7f6SOla Lilja 		frame_per = protdesc->frame_period;
250*3592b7f6SOla Lilja 		break;
251*3592b7f6SOla Lilja 	default:
252*3592b7f6SOla Lilja 		dev_err(msp->dev, "%s: ERROR: Unknown protocol (%d)!\n",
253*3592b7f6SOla Lilja 			__func__,
254*3592b7f6SOla Lilja 			config->protocol);
255*3592b7f6SOla Lilja 		return -EINVAL;
256*3592b7f6SOla Lilja 	}
257*3592b7f6SOla Lilja 
258*3592b7f6SOla Lilja 	temp_reg = (sck_div - 1) & SCK_DIV_MASK;
259*3592b7f6SOla Lilja 	temp_reg |= FRAME_WIDTH_BITS(frame_width);
260*3592b7f6SOla Lilja 	temp_reg |= FRAME_PERIOD_BITS(frame_per);
261*3592b7f6SOla Lilja 	writel(temp_reg, msp->registers + MSP_SRG);
262*3592b7f6SOla Lilja 
263*3592b7f6SOla Lilja 	msp->f_bitclk = (config->f_inputclk)/(sck_div + 1);
264*3592b7f6SOla Lilja 
265*3592b7f6SOla Lilja 	/* Enable bit-clock */
266*3592b7f6SOla Lilja 	udelay(100);
267*3592b7f6SOla Lilja 	reg_val_GCR = readl(msp->registers + MSP_GCR);
268*3592b7f6SOla Lilja 	writel(reg_val_GCR | SRG_ENABLE, msp->registers + MSP_GCR);
269*3592b7f6SOla Lilja 	udelay(100);
270*3592b7f6SOla Lilja 
271*3592b7f6SOla Lilja 	return 0;
272*3592b7f6SOla Lilja }
273*3592b7f6SOla Lilja 
274*3592b7f6SOla Lilja static int configure_multichannel(struct ux500_msp *msp,
275*3592b7f6SOla Lilja 				struct ux500_msp_config *config)
276*3592b7f6SOla Lilja {
277*3592b7f6SOla Lilja 	struct msp_protdesc *protdesc;
278*3592b7f6SOla Lilja 	struct msp_multichannel_config *mcfg;
279*3592b7f6SOla Lilja 	u32 reg_val_MCR;
280*3592b7f6SOla Lilja 
281*3592b7f6SOla Lilja 	if (config->default_protdesc == 1) {
282*3592b7f6SOla Lilja 		if (config->protocol >= MSP_INVALID_PROTOCOL) {
283*3592b7f6SOla Lilja 			dev_err(msp->dev,
284*3592b7f6SOla Lilja 				"%s: ERROR: Invalid protocol (%d)!\n",
285*3592b7f6SOla Lilja 				__func__, config->protocol);
286*3592b7f6SOla Lilja 			return -EINVAL;
287*3592b7f6SOla Lilja 		}
288*3592b7f6SOla Lilja 		protdesc = (struct msp_protdesc *)
289*3592b7f6SOla Lilja 				&prot_descs[config->protocol];
290*3592b7f6SOla Lilja 	} else {
291*3592b7f6SOla Lilja 		protdesc = (struct msp_protdesc *)&config->protdesc;
292*3592b7f6SOla Lilja 	}
293*3592b7f6SOla Lilja 
294*3592b7f6SOla Lilja 	mcfg = &config->multichannel_config;
295*3592b7f6SOla Lilja 	if (mcfg->tx_multichannel_enable) {
296*3592b7f6SOla Lilja 		if (protdesc->tx_phase_mode == MSP_SINGLE_PHASE) {
297*3592b7f6SOla Lilja 			reg_val_MCR = readl(msp->registers + MSP_MCR);
298*3592b7f6SOla Lilja 			writel(reg_val_MCR | (mcfg->tx_multichannel_enable ?
299*3592b7f6SOla Lilja 						1 << TMCEN_BIT : 0),
300*3592b7f6SOla Lilja 				msp->registers + MSP_MCR);
301*3592b7f6SOla Lilja 			writel(mcfg->tx_channel_0_enable,
302*3592b7f6SOla Lilja 				msp->registers + MSP_TCE0);
303*3592b7f6SOla Lilja 			writel(mcfg->tx_channel_1_enable,
304*3592b7f6SOla Lilja 				msp->registers + MSP_TCE1);
305*3592b7f6SOla Lilja 			writel(mcfg->tx_channel_2_enable,
306*3592b7f6SOla Lilja 				msp->registers + MSP_TCE2);
307*3592b7f6SOla Lilja 			writel(mcfg->tx_channel_3_enable,
308*3592b7f6SOla Lilja 				msp->registers + MSP_TCE3);
309*3592b7f6SOla Lilja 		} else {
310*3592b7f6SOla Lilja 			dev_err(msp->dev,
311*3592b7f6SOla Lilja 				"%s: ERROR: Only single-phase supported (TX-mode: %d)!\n",
312*3592b7f6SOla Lilja 				__func__, protdesc->tx_phase_mode);
313*3592b7f6SOla Lilja 			return -EINVAL;
314*3592b7f6SOla Lilja 		}
315*3592b7f6SOla Lilja 	}
316*3592b7f6SOla Lilja 	if (mcfg->rx_multichannel_enable) {
317*3592b7f6SOla Lilja 		if (protdesc->rx_phase_mode == MSP_SINGLE_PHASE) {
318*3592b7f6SOla Lilja 			reg_val_MCR = readl(msp->registers + MSP_MCR);
319*3592b7f6SOla Lilja 			writel(reg_val_MCR | (mcfg->rx_multichannel_enable ?
320*3592b7f6SOla Lilja 						1 << RMCEN_BIT : 0),
321*3592b7f6SOla Lilja 				msp->registers + MSP_MCR);
322*3592b7f6SOla Lilja 			writel(mcfg->rx_channel_0_enable,
323*3592b7f6SOla Lilja 					msp->registers + MSP_RCE0);
324*3592b7f6SOla Lilja 			writel(mcfg->rx_channel_1_enable,
325*3592b7f6SOla Lilja 					msp->registers + MSP_RCE1);
326*3592b7f6SOla Lilja 			writel(mcfg->rx_channel_2_enable,
327*3592b7f6SOla Lilja 					msp->registers + MSP_RCE2);
328*3592b7f6SOla Lilja 			writel(mcfg->rx_channel_3_enable,
329*3592b7f6SOla Lilja 					msp->registers + MSP_RCE3);
330*3592b7f6SOla Lilja 		} else {
331*3592b7f6SOla Lilja 			dev_err(msp->dev,
332*3592b7f6SOla Lilja 				"%s: ERROR: Only single-phase supported (RX-mode: %d)!\n",
333*3592b7f6SOla Lilja 				__func__, protdesc->rx_phase_mode);
334*3592b7f6SOla Lilja 			return -EINVAL;
335*3592b7f6SOla Lilja 		}
336*3592b7f6SOla Lilja 		if (mcfg->rx_comparison_enable_mode) {
337*3592b7f6SOla Lilja 			reg_val_MCR = readl(msp->registers + MSP_MCR);
338*3592b7f6SOla Lilja 			writel(reg_val_MCR |
339*3592b7f6SOla Lilja 				(mcfg->rx_comparison_enable_mode << RCMPM_BIT),
340*3592b7f6SOla Lilja 				msp->registers + MSP_MCR);
341*3592b7f6SOla Lilja 
342*3592b7f6SOla Lilja 			writel(mcfg->comparison_mask,
343*3592b7f6SOla Lilja 					msp->registers + MSP_RCM);
344*3592b7f6SOla Lilja 			writel(mcfg->comparison_value,
345*3592b7f6SOla Lilja 					msp->registers + MSP_RCV);
346*3592b7f6SOla Lilja 
347*3592b7f6SOla Lilja 		}
348*3592b7f6SOla Lilja 	}
349*3592b7f6SOla Lilja 
350*3592b7f6SOla Lilja 	return 0;
351*3592b7f6SOla Lilja }
352*3592b7f6SOla Lilja 
353*3592b7f6SOla Lilja static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
354*3592b7f6SOla Lilja {
355*3592b7f6SOla Lilja 	int status = 0;
356*3592b7f6SOla Lilja 	u32 reg_val_DMACR, reg_val_GCR;
357*3592b7f6SOla Lilja 
358*3592b7f6SOla Lilja 	/* Check msp state whether in RUN or CONFIGURED Mode */
359*3592b7f6SOla Lilja 	if ((msp->msp_state == MSP_STATE_IDLE) && (msp->plat_init)) {
360*3592b7f6SOla Lilja 		status = msp->plat_init();
361*3592b7f6SOla Lilja 		if (status) {
362*3592b7f6SOla Lilja 			dev_err(msp->dev, "%s: ERROR: Failed to init MSP (%d)!\n",
363*3592b7f6SOla Lilja 				__func__, status);
364*3592b7f6SOla Lilja 			return status;
365*3592b7f6SOla Lilja 		}
366*3592b7f6SOla Lilja 	}
367*3592b7f6SOla Lilja 
368*3592b7f6SOla Lilja 	/* Configure msp with protocol dependent settings */
369*3592b7f6SOla Lilja 	configure_protocol(msp, config);
370*3592b7f6SOla Lilja 	setup_bitclk(msp, config);
371*3592b7f6SOla Lilja 	if (config->multichannel_configured == 1) {
372*3592b7f6SOla Lilja 		status = configure_multichannel(msp, config);
373*3592b7f6SOla Lilja 		if (status)
374*3592b7f6SOla Lilja 			dev_warn(msp->dev,
375*3592b7f6SOla Lilja 				"%s: WARN: configure_multichannel failed (%d)!\n",
376*3592b7f6SOla Lilja 				__func__, status);
377*3592b7f6SOla Lilja 	}
378*3592b7f6SOla Lilja 
379*3592b7f6SOla Lilja 	/* Make sure the correct DMA-directions are configured */
380*3592b7f6SOla Lilja 	if ((config->direction & MSP_DIR_RX) && (!msp->dma_cfg_rx)) {
381*3592b7f6SOla Lilja 		dev_err(msp->dev, "%s: ERROR: MSP RX-mode is not configured!",
382*3592b7f6SOla Lilja 			__func__);
383*3592b7f6SOla Lilja 		return -EINVAL;
384*3592b7f6SOla Lilja 	}
385*3592b7f6SOla Lilja 	if ((config->direction == MSP_DIR_TX) && (!msp->dma_cfg_tx)) {
386*3592b7f6SOla Lilja 		dev_err(msp->dev, "%s: ERROR: MSP TX-mode is not configured!",
387*3592b7f6SOla Lilja 			__func__);
388*3592b7f6SOla Lilja 		return -EINVAL;
389*3592b7f6SOla Lilja 	}
390*3592b7f6SOla Lilja 
391*3592b7f6SOla Lilja 	reg_val_DMACR = readl(msp->registers + MSP_DMACR);
392*3592b7f6SOla Lilja 	if (config->direction & MSP_DIR_RX)
393*3592b7f6SOla Lilja 		reg_val_DMACR |= RX_DMA_ENABLE;
394*3592b7f6SOla Lilja 	if (config->direction & MSP_DIR_TX)
395*3592b7f6SOla Lilja 		reg_val_DMACR |= TX_DMA_ENABLE;
396*3592b7f6SOla Lilja 	writel(reg_val_DMACR, msp->registers + MSP_DMACR);
397*3592b7f6SOla Lilja 
398*3592b7f6SOla Lilja 	writel(config->iodelay, msp->registers + MSP_IODLY);
399*3592b7f6SOla Lilja 
400*3592b7f6SOla Lilja 	/* Enable frame generation logic */
401*3592b7f6SOla Lilja 	reg_val_GCR = readl(msp->registers + MSP_GCR);
402*3592b7f6SOla Lilja 	writel(reg_val_GCR | FRAME_GEN_ENABLE, msp->registers + MSP_GCR);
403*3592b7f6SOla Lilja 
404*3592b7f6SOla Lilja 	return status;
405*3592b7f6SOla Lilja }
406*3592b7f6SOla Lilja 
407*3592b7f6SOla Lilja static void flush_fifo_rx(struct ux500_msp *msp)
408*3592b7f6SOla Lilja {
409*3592b7f6SOla Lilja 	u32 reg_val_DR, reg_val_GCR, reg_val_FLR;
410*3592b7f6SOla Lilja 	u32 limit = 32;
411*3592b7f6SOla Lilja 
412*3592b7f6SOla Lilja 	reg_val_GCR = readl(msp->registers + MSP_GCR);
413*3592b7f6SOla Lilja 	writel(reg_val_GCR | RX_ENABLE, msp->registers + MSP_GCR);
414*3592b7f6SOla Lilja 
415*3592b7f6SOla Lilja 	reg_val_FLR = readl(msp->registers + MSP_FLR);
416*3592b7f6SOla Lilja 	while (!(reg_val_FLR & RX_FIFO_EMPTY) && limit--) {
417*3592b7f6SOla Lilja 		reg_val_DR = readl(msp->registers + MSP_DR);
418*3592b7f6SOla Lilja 		reg_val_FLR = readl(msp->registers + MSP_FLR);
419*3592b7f6SOla Lilja 	}
420*3592b7f6SOla Lilja 
421*3592b7f6SOla Lilja 	writel(reg_val_GCR, msp->registers + MSP_GCR);
422*3592b7f6SOla Lilja }
423*3592b7f6SOla Lilja 
424*3592b7f6SOla Lilja static void flush_fifo_tx(struct ux500_msp *msp)
425*3592b7f6SOla Lilja {
426*3592b7f6SOla Lilja 	u32 reg_val_TSTDR, reg_val_GCR, reg_val_FLR;
427*3592b7f6SOla Lilja 	u32 limit = 32;
428*3592b7f6SOla Lilja 
429*3592b7f6SOla Lilja 	reg_val_GCR = readl(msp->registers + MSP_GCR);
430*3592b7f6SOla Lilja 	writel(reg_val_GCR | TX_ENABLE, msp->registers + MSP_GCR);
431*3592b7f6SOla Lilja 	writel(MSP_ITCR_ITEN | MSP_ITCR_TESTFIFO, msp->registers + MSP_ITCR);
432*3592b7f6SOla Lilja 
433*3592b7f6SOla Lilja 	reg_val_FLR = readl(msp->registers + MSP_FLR);
434*3592b7f6SOla Lilja 	while (!(reg_val_FLR & TX_FIFO_EMPTY) && limit--) {
435*3592b7f6SOla Lilja 		reg_val_TSTDR = readl(msp->registers + MSP_TSTDR);
436*3592b7f6SOla Lilja 		reg_val_FLR = readl(msp->registers + MSP_FLR);
437*3592b7f6SOla Lilja 	}
438*3592b7f6SOla Lilja 	writel(0x0, msp->registers + MSP_ITCR);
439*3592b7f6SOla Lilja 	writel(reg_val_GCR, msp->registers + MSP_GCR);
440*3592b7f6SOla Lilja }
441*3592b7f6SOla Lilja 
442*3592b7f6SOla Lilja int ux500_msp_i2s_open(struct ux500_msp *msp,
443*3592b7f6SOla Lilja 		struct ux500_msp_config *config)
444*3592b7f6SOla Lilja {
445*3592b7f6SOla Lilja 	u32 old_reg, new_reg, mask;
446*3592b7f6SOla Lilja 	int res;
447*3592b7f6SOla Lilja 	unsigned int tx_sel, rx_sel, tx_busy, rx_busy;
448*3592b7f6SOla Lilja 
449*3592b7f6SOla Lilja 	if (in_interrupt()) {
450*3592b7f6SOla Lilja 		dev_err(msp->dev,
451*3592b7f6SOla Lilja 			"%s: ERROR: Open called in interrupt context!\n",
452*3592b7f6SOla Lilja 			__func__);
453*3592b7f6SOla Lilja 		return -1;
454*3592b7f6SOla Lilja 	}
455*3592b7f6SOla Lilja 
456*3592b7f6SOla Lilja 	tx_sel = (config->direction & MSP_DIR_TX) > 0;
457*3592b7f6SOla Lilja 	rx_sel = (config->direction & MSP_DIR_RX) > 0;
458*3592b7f6SOla Lilja 	if (!tx_sel && !rx_sel) {
459*3592b7f6SOla Lilja 		dev_err(msp->dev, "%s: Error: No direction selected!\n",
460*3592b7f6SOla Lilja 			__func__);
461*3592b7f6SOla Lilja 		return -EINVAL;
462*3592b7f6SOla Lilja 	}
463*3592b7f6SOla Lilja 
464*3592b7f6SOla Lilja 	tx_busy = (msp->dir_busy & MSP_DIR_TX) > 0;
465*3592b7f6SOla Lilja 	rx_busy = (msp->dir_busy & MSP_DIR_RX) > 0;
466*3592b7f6SOla Lilja 	if (tx_busy && tx_sel) {
467*3592b7f6SOla Lilja 		dev_err(msp->dev, "%s: Error: TX is in use!\n", __func__);
468*3592b7f6SOla Lilja 		return -EBUSY;
469*3592b7f6SOla Lilja 	}
470*3592b7f6SOla Lilja 	if (rx_busy && rx_sel) {
471*3592b7f6SOla Lilja 		dev_err(msp->dev, "%s: Error: RX is in use!\n", __func__);
472*3592b7f6SOla Lilja 		return -EBUSY;
473*3592b7f6SOla Lilja 	}
474*3592b7f6SOla Lilja 
475*3592b7f6SOla Lilja 	msp->dir_busy |= (tx_sel ? MSP_DIR_TX : 0) | (rx_sel ? MSP_DIR_RX : 0);
476*3592b7f6SOla Lilja 
477*3592b7f6SOla Lilja 	/* First do the global config register */
478*3592b7f6SOla Lilja 	mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK |
479*3592b7f6SOla Lilja 	    TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
480*3592b7f6SOla Lilja 	    RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |
481*3592b7f6SOla Lilja 	    LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
482*3592b7f6SOla Lilja 
483*3592b7f6SOla Lilja 	new_reg = (config->tx_clk_sel | config->rx_clk_sel |
484*3592b7f6SOla Lilja 		config->rx_fsync_pol | config->tx_fsync_pol |
485*3592b7f6SOla Lilja 		config->rx_fsync_sel | config->tx_fsync_sel |
486*3592b7f6SOla Lilja 		config->rx_fifo_config | config->tx_fifo_config |
487*3592b7f6SOla Lilja 		config->srg_clk_sel | config->loopback_enable |
488*3592b7f6SOla Lilja 		config->tx_data_enable);
489*3592b7f6SOla Lilja 
490*3592b7f6SOla Lilja 	old_reg = readl(msp->registers + MSP_GCR);
491*3592b7f6SOla Lilja 	old_reg &= ~mask;
492*3592b7f6SOla Lilja 	new_reg |= old_reg;
493*3592b7f6SOla Lilja 	writel(new_reg, msp->registers + MSP_GCR);
494*3592b7f6SOla Lilja 
495*3592b7f6SOla Lilja 	res = enable_msp(msp, config);
496*3592b7f6SOla Lilja 	if (res < 0) {
497*3592b7f6SOla Lilja 		dev_err(msp->dev, "%s: ERROR: enable_msp failed (%d)!\n",
498*3592b7f6SOla Lilja 			__func__, res);
499*3592b7f6SOla Lilja 		return -EBUSY;
500*3592b7f6SOla Lilja 	}
501*3592b7f6SOla Lilja 	if (config->loopback_enable & 0x80)
502*3592b7f6SOla Lilja 		msp->loopback_enable = 1;
503*3592b7f6SOla Lilja 
504*3592b7f6SOla Lilja 	/* Flush FIFOs */
505*3592b7f6SOla Lilja 	flush_fifo_tx(msp);
506*3592b7f6SOla Lilja 	flush_fifo_rx(msp);
507*3592b7f6SOla Lilja 
508*3592b7f6SOla Lilja 	msp->msp_state = MSP_STATE_CONFIGURED;
509*3592b7f6SOla Lilja 	return 0;
510*3592b7f6SOla Lilja }
511*3592b7f6SOla Lilja 
512*3592b7f6SOla Lilja static void disable_msp_rx(struct ux500_msp *msp)
513*3592b7f6SOla Lilja {
514*3592b7f6SOla Lilja 	u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
515*3592b7f6SOla Lilja 
516*3592b7f6SOla Lilja 	reg_val_GCR = readl(msp->registers + MSP_GCR);
517*3592b7f6SOla Lilja 	writel(reg_val_GCR & ~RX_ENABLE, msp->registers + MSP_GCR);
518*3592b7f6SOla Lilja 	reg_val_DMACR = readl(msp->registers + MSP_DMACR);
519*3592b7f6SOla Lilja 	writel(reg_val_DMACR & ~RX_DMA_ENABLE, msp->registers + MSP_DMACR);
520*3592b7f6SOla Lilja 	reg_val_IMSC = readl(msp->registers + MSP_IMSC);
521*3592b7f6SOla Lilja 	writel(reg_val_IMSC &
522*3592b7f6SOla Lilja 			~(RX_SERVICE_INT | RX_OVERRUN_ERROR_INT),
523*3592b7f6SOla Lilja 			msp->registers + MSP_IMSC);
524*3592b7f6SOla Lilja 
525*3592b7f6SOla Lilja 	msp->dir_busy &= ~MSP_DIR_RX;
526*3592b7f6SOla Lilja }
527*3592b7f6SOla Lilja 
528*3592b7f6SOla Lilja static void disable_msp_tx(struct ux500_msp *msp)
529*3592b7f6SOla Lilja {
530*3592b7f6SOla Lilja 	u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
531*3592b7f6SOla Lilja 
532*3592b7f6SOla Lilja 	reg_val_GCR = readl(msp->registers + MSP_GCR);
533*3592b7f6SOla Lilja 	writel(reg_val_GCR & ~TX_ENABLE, msp->registers + MSP_GCR);
534*3592b7f6SOla Lilja 	reg_val_DMACR = readl(msp->registers + MSP_DMACR);
535*3592b7f6SOla Lilja 	writel(reg_val_DMACR & ~TX_DMA_ENABLE, msp->registers + MSP_DMACR);
536*3592b7f6SOla Lilja 	reg_val_IMSC = readl(msp->registers + MSP_IMSC);
537*3592b7f6SOla Lilja 	writel(reg_val_IMSC &
538*3592b7f6SOla Lilja 			~(TX_SERVICE_INT | TX_UNDERRUN_ERR_INT),
539*3592b7f6SOla Lilja 			msp->registers + MSP_IMSC);
540*3592b7f6SOla Lilja 
541*3592b7f6SOla Lilja 	msp->dir_busy &= ~MSP_DIR_TX;
542*3592b7f6SOla Lilja }
543*3592b7f6SOla Lilja 
544*3592b7f6SOla Lilja static int disable_msp(struct ux500_msp *msp, unsigned int dir)
545*3592b7f6SOla Lilja {
546*3592b7f6SOla Lilja 	u32 reg_val_GCR;
547*3592b7f6SOla Lilja 	int status = 0;
548*3592b7f6SOla Lilja 	unsigned int disable_tx, disable_rx;
549*3592b7f6SOla Lilja 
550*3592b7f6SOla Lilja 	reg_val_GCR = readl(msp->registers + MSP_GCR);
551*3592b7f6SOla Lilja 	disable_tx = dir & MSP_DIR_TX;
552*3592b7f6SOla Lilja 	disable_rx = dir & MSP_DIR_TX;
553*3592b7f6SOla Lilja 	if (disable_tx && disable_rx) {
554*3592b7f6SOla Lilja 		reg_val_GCR = readl(msp->registers + MSP_GCR);
555*3592b7f6SOla Lilja 		writel(reg_val_GCR | LOOPBACK_MASK,
556*3592b7f6SOla Lilja 				msp->registers + MSP_GCR);
557*3592b7f6SOla Lilja 
558*3592b7f6SOla Lilja 		/* Flush TX-FIFO */
559*3592b7f6SOla Lilja 		flush_fifo_tx(msp);
560*3592b7f6SOla Lilja 
561*3592b7f6SOla Lilja 		/* Disable TX-channel */
562*3592b7f6SOla Lilja 		writel((readl(msp->registers + MSP_GCR) &
563*3592b7f6SOla Lilja 			       (~TX_ENABLE)), msp->registers + MSP_GCR);
564*3592b7f6SOla Lilja 
565*3592b7f6SOla Lilja 		/* Flush RX-FIFO */
566*3592b7f6SOla Lilja 		flush_fifo_rx(msp);
567*3592b7f6SOla Lilja 
568*3592b7f6SOla Lilja 		/* Disable Loopback and Receive channel */
569*3592b7f6SOla Lilja 		writel((readl(msp->registers + MSP_GCR) &
570*3592b7f6SOla Lilja 				(~(RX_ENABLE | LOOPBACK_MASK))),
571*3592b7f6SOla Lilja 				msp->registers + MSP_GCR);
572*3592b7f6SOla Lilja 
573*3592b7f6SOla Lilja 		disable_msp_tx(msp);
574*3592b7f6SOla Lilja 		disable_msp_rx(msp);
575*3592b7f6SOla Lilja 	} else if (disable_tx)
576*3592b7f6SOla Lilja 		disable_msp_tx(msp);
577*3592b7f6SOla Lilja 	else if (disable_rx)
578*3592b7f6SOla Lilja 		disable_msp_rx(msp);
579*3592b7f6SOla Lilja 
580*3592b7f6SOla Lilja 	return status;
581*3592b7f6SOla Lilja }
582*3592b7f6SOla Lilja 
583*3592b7f6SOla Lilja int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
584*3592b7f6SOla Lilja {
585*3592b7f6SOla Lilja 	u32 reg_val_GCR, enable_bit;
586*3592b7f6SOla Lilja 
587*3592b7f6SOla Lilja 	if (msp->msp_state == MSP_STATE_IDLE) {
588*3592b7f6SOla Lilja 		dev_err(msp->dev, "%s: ERROR: MSP is not configured!\n",
589*3592b7f6SOla Lilja 			__func__);
590*3592b7f6SOla Lilja 		return -EINVAL;
591*3592b7f6SOla Lilja 	}
592*3592b7f6SOla Lilja 
593*3592b7f6SOla Lilja 	switch (cmd) {
594*3592b7f6SOla Lilja 	case SNDRV_PCM_TRIGGER_START:
595*3592b7f6SOla Lilja 	case SNDRV_PCM_TRIGGER_RESUME:
596*3592b7f6SOla Lilja 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
597*3592b7f6SOla Lilja 		if (direction == SNDRV_PCM_STREAM_PLAYBACK)
598*3592b7f6SOla Lilja 			enable_bit = TX_ENABLE;
599*3592b7f6SOla Lilja 		else
600*3592b7f6SOla Lilja 			enable_bit = RX_ENABLE;
601*3592b7f6SOla Lilja 		reg_val_GCR = readl(msp->registers + MSP_GCR);
602*3592b7f6SOla Lilja 		writel(reg_val_GCR | enable_bit, msp->registers + MSP_GCR);
603*3592b7f6SOla Lilja 		break;
604*3592b7f6SOla Lilja 
605*3592b7f6SOla Lilja 	case SNDRV_PCM_TRIGGER_STOP:
606*3592b7f6SOla Lilja 	case SNDRV_PCM_TRIGGER_SUSPEND:
607*3592b7f6SOla Lilja 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
608*3592b7f6SOla Lilja 		if (direction == SNDRV_PCM_STREAM_PLAYBACK)
609*3592b7f6SOla Lilja 			disable_msp_tx(msp);
610*3592b7f6SOla Lilja 		else
611*3592b7f6SOla Lilja 			disable_msp_rx(msp);
612*3592b7f6SOla Lilja 		break;
613*3592b7f6SOla Lilja 	default:
614*3592b7f6SOla Lilja 		return -EINVAL;
615*3592b7f6SOla Lilja 		break;
616*3592b7f6SOla Lilja 	}
617*3592b7f6SOla Lilja 
618*3592b7f6SOla Lilja 	return 0;
619*3592b7f6SOla Lilja }
620*3592b7f6SOla Lilja 
621*3592b7f6SOla Lilja int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
622*3592b7f6SOla Lilja {
623*3592b7f6SOla Lilja 	int status = 0;
624*3592b7f6SOla Lilja 
625*3592b7f6SOla Lilja 	dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
626*3592b7f6SOla Lilja 
627*3592b7f6SOla Lilja 	status = disable_msp(msp, dir);
628*3592b7f6SOla Lilja 	if (msp->dir_busy == 0) {
629*3592b7f6SOla Lilja 		/* disable sample rate and frame generators */
630*3592b7f6SOla Lilja 		msp->msp_state = MSP_STATE_IDLE;
631*3592b7f6SOla Lilja 		writel((readl(msp->registers + MSP_GCR) &
632*3592b7f6SOla Lilja 			       (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
633*3592b7f6SOla Lilja 			      msp->registers + MSP_GCR);
634*3592b7f6SOla Lilja 		if (msp->plat_exit)
635*3592b7f6SOla Lilja 			status = msp->plat_exit();
636*3592b7f6SOla Lilja 			if (status)
637*3592b7f6SOla Lilja 				dev_warn(msp->dev,
638*3592b7f6SOla Lilja 					"%s: WARN: ux500_msp_i2s_exit failed (%d)!\n",
639*3592b7f6SOla Lilja 					__func__, status);
640*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_GCR);
641*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_TCF);
642*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_RCF);
643*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_DMACR);
644*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_SRG);
645*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_MCR);
646*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_RCM);
647*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_RCV);
648*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_TCE0);
649*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_TCE1);
650*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_TCE2);
651*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_TCE3);
652*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_RCE0);
653*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_RCE1);
654*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_RCE2);
655*3592b7f6SOla Lilja 		writel(0, msp->registers + MSP_RCE3);
656*3592b7f6SOla Lilja 	}
657*3592b7f6SOla Lilja 
658*3592b7f6SOla Lilja 	return status;
659*3592b7f6SOla Lilja 
660*3592b7f6SOla Lilja }
661*3592b7f6SOla Lilja 
662*3592b7f6SOla Lilja int ux500_msp_i2s_init_msp(struct platform_device *pdev,
663*3592b7f6SOla Lilja 			struct ux500_msp **msp_p,
664*3592b7f6SOla Lilja 			struct msp_i2s_platform_data *platform_data)
665*3592b7f6SOla Lilja {
666*3592b7f6SOla Lilja 	int ret = 0;
667*3592b7f6SOla Lilja 	struct resource *res = NULL;
668*3592b7f6SOla Lilja 	struct i2s_controller *i2s_cont;
669*3592b7f6SOla Lilja 	struct ux500_msp *msp;
670*3592b7f6SOla Lilja 
671*3592b7f6SOla Lilja 	dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
672*3592b7f6SOla Lilja 		pdev->name, platform_data->id);
673*3592b7f6SOla Lilja 
674*3592b7f6SOla Lilja 	*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
675*3592b7f6SOla Lilja 	msp = *msp_p;
676*3592b7f6SOla Lilja 
677*3592b7f6SOla Lilja 	msp->id = platform_data->id;
678*3592b7f6SOla Lilja 	msp->dev = &pdev->dev;
679*3592b7f6SOla Lilja 	msp->plat_init = platform_data->msp_i2s_init;
680*3592b7f6SOla Lilja 	msp->plat_exit = platform_data->msp_i2s_exit;
681*3592b7f6SOla Lilja 	msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
682*3592b7f6SOla Lilja 	msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
683*3592b7f6SOla Lilja 
684*3592b7f6SOla Lilja 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
685*3592b7f6SOla Lilja 	if (res == NULL) {
686*3592b7f6SOla Lilja 		dev_err(&pdev->dev, "%s: ERROR: Unable to get resource!\n",
687*3592b7f6SOla Lilja 			__func__);
688*3592b7f6SOla Lilja 		ret = -ENOMEM;
689*3592b7f6SOla Lilja 		goto err_res;
690*3592b7f6SOla Lilja 	}
691*3592b7f6SOla Lilja 
692*3592b7f6SOla Lilja 	msp->registers = ioremap(res->start, (res->end - res->start + 1));
693*3592b7f6SOla Lilja 	if (msp->registers == NULL) {
694*3592b7f6SOla Lilja 		dev_err(&pdev->dev, "%s: ERROR: ioremap failed!\n", __func__);
695*3592b7f6SOla Lilja 		ret = -ENOMEM;
696*3592b7f6SOla Lilja 		goto err_res;
697*3592b7f6SOla Lilja 	}
698*3592b7f6SOla Lilja 
699*3592b7f6SOla Lilja 	msp->msp_state = MSP_STATE_IDLE;
700*3592b7f6SOla Lilja 	msp->loopback_enable = 0;
701*3592b7f6SOla Lilja 
702*3592b7f6SOla Lilja 	/* I2S-controller is allocated and added in I2S controller class. */
703*3592b7f6SOla Lilja 	i2s_cont = devm_kzalloc(&pdev->dev, sizeof(*i2s_cont), GFP_KERNEL);
704*3592b7f6SOla Lilja 	if (!i2s_cont) {
705*3592b7f6SOla Lilja 		dev_err(&pdev->dev,
706*3592b7f6SOla Lilja 			"%s: ERROR: Failed to allocate I2S-controller!\n",
707*3592b7f6SOla Lilja 			__func__);
708*3592b7f6SOla Lilja 		goto err_i2s_cont;
709*3592b7f6SOla Lilja 	}
710*3592b7f6SOla Lilja 	i2s_cont->dev.parent = &pdev->dev;
711*3592b7f6SOla Lilja 	i2s_cont->data = (void *)msp;
712*3592b7f6SOla Lilja 	i2s_cont->id = (s16)msp->id;
713*3592b7f6SOla Lilja 	snprintf(i2s_cont->name, sizeof(i2s_cont->name), "ux500-msp-i2s.%04x",
714*3592b7f6SOla Lilja 		msp->id);
715*3592b7f6SOla Lilja 	dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
716*3592b7f6SOla Lilja 	msp->i2s_cont = i2s_cont;
717*3592b7f6SOla Lilja 
718*3592b7f6SOla Lilja 	return 0;
719*3592b7f6SOla Lilja 
720*3592b7f6SOla Lilja err_i2s_cont:
721*3592b7f6SOla Lilja 	iounmap(msp->registers);
722*3592b7f6SOla Lilja 
723*3592b7f6SOla Lilja err_res:
724*3592b7f6SOla Lilja 	devm_kfree(&pdev->dev, msp);
725*3592b7f6SOla Lilja 
726*3592b7f6SOla Lilja 	return ret;
727*3592b7f6SOla Lilja }
728*3592b7f6SOla Lilja 
729*3592b7f6SOla Lilja void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
730*3592b7f6SOla Lilja 			struct ux500_msp *msp)
731*3592b7f6SOla Lilja {
732*3592b7f6SOla Lilja 	dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id);
733*3592b7f6SOla Lilja 
734*3592b7f6SOla Lilja 	device_unregister(&msp->i2s_cont->dev);
735*3592b7f6SOla Lilja 	devm_kfree(&pdev->dev, msp->i2s_cont);
736*3592b7f6SOla Lilja 
737*3592b7f6SOla Lilja 	iounmap(msp->registers);
738*3592b7f6SOla Lilja 
739*3592b7f6SOla Lilja 	devm_kfree(&pdev->dev, msp);
740*3592b7f6SOla Lilja }
741*3592b7f6SOla Lilja 
742*3592b7f6SOla Lilja MODULE_LICENSE("GPLv2");
743