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