1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (C) 2012 Samsung Electronics
3*4882a593Smuzhiyun * R. Chandrasekar <rcsekar@samsung.com>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <asm/arch/clk.h>
9*4882a593Smuzhiyun #include <asm/arch/pinmux.h>
10*4882a593Smuzhiyun #include <asm/arch/i2s-regs.h>
11*4882a593Smuzhiyun #include <asm/io.h>
12*4882a593Smuzhiyun #include <common.h>
13*4882a593Smuzhiyun #include <sound.h>
14*4882a593Smuzhiyun #include <i2s.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #define FIC_TX2COUNT(x) (((x) >> 24) & 0xf)
17*4882a593Smuzhiyun #define FIC_TX1COUNT(x) (((x) >> 16) & 0xf)
18*4882a593Smuzhiyun #define FIC_TXCOUNT(x) (((x) >> 8) & 0xf)
19*4882a593Smuzhiyun #define FIC_RXCOUNT(x) (((x) >> 0) & 0xf)
20*4882a593Smuzhiyun #define FICS_TXCOUNT(x) (((x) >> 8) & 0x7f)
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #define TIMEOUT_I2S_TX 100 /* i2s transfer timeout */
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun /*
25*4882a593Smuzhiyun * Sets the frame size for I2S LR clock
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun * @param i2s_reg i2s regiter address
28*4882a593Smuzhiyun * @param rfs Frame Size
29*4882a593Smuzhiyun */
i2s_set_lr_framesize(struct i2s_reg * i2s_reg,unsigned int rfs)30*4882a593Smuzhiyun static void i2s_set_lr_framesize(struct i2s_reg *i2s_reg, unsigned int rfs)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun unsigned int mod = readl(&i2s_reg->mod);
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun mod &= ~MOD_RCLK_MASK;
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun switch (rfs) {
37*4882a593Smuzhiyun case 768:
38*4882a593Smuzhiyun mod |= MOD_RCLK_768FS;
39*4882a593Smuzhiyun break;
40*4882a593Smuzhiyun case 512:
41*4882a593Smuzhiyun mod |= MOD_RCLK_512FS;
42*4882a593Smuzhiyun break;
43*4882a593Smuzhiyun case 384:
44*4882a593Smuzhiyun mod |= MOD_RCLK_384FS;
45*4882a593Smuzhiyun break;
46*4882a593Smuzhiyun default:
47*4882a593Smuzhiyun mod |= MOD_RCLK_256FS;
48*4882a593Smuzhiyun break;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun writel(mod, &i2s_reg->mod);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /*
55*4882a593Smuzhiyun * Sets the i2s transfer control
56*4882a593Smuzhiyun *
57*4882a593Smuzhiyun * @param i2s_reg i2s regiter address
58*4882a593Smuzhiyun * @param on 1 enable tx , 0 disable tx transfer
59*4882a593Smuzhiyun */
i2s_txctrl(struct i2s_reg * i2s_reg,int on)60*4882a593Smuzhiyun static void i2s_txctrl(struct i2s_reg *i2s_reg, int on)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun unsigned int con = readl(&i2s_reg->con);
63*4882a593Smuzhiyun unsigned int mod = readl(&i2s_reg->mod) & ~MOD_MASK;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (on) {
66*4882a593Smuzhiyun con |= CON_ACTIVE;
67*4882a593Smuzhiyun con &= ~CON_TXCH_PAUSE;
68*4882a593Smuzhiyun } else {
69*4882a593Smuzhiyun con |= CON_TXCH_PAUSE;
70*4882a593Smuzhiyun con &= ~CON_ACTIVE;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun writel(mod, &i2s_reg->mod);
74*4882a593Smuzhiyun writel(con, &i2s_reg->con);
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /*
78*4882a593Smuzhiyun * set the bit clock frame size (in multiples of LRCLK)
79*4882a593Smuzhiyun *
80*4882a593Smuzhiyun * @param i2s_reg i2s regiter address
81*4882a593Smuzhiyun * @param bfs bit Frame Size
82*4882a593Smuzhiyun */
i2s_set_bitclk_framesize(struct i2s_reg * i2s_reg,unsigned bfs)83*4882a593Smuzhiyun static void i2s_set_bitclk_framesize(struct i2s_reg *i2s_reg, unsigned bfs)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun unsigned int mod = readl(&i2s_reg->mod);
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun mod &= ~MOD_BCLK_MASK;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun switch (bfs) {
90*4882a593Smuzhiyun case 48:
91*4882a593Smuzhiyun mod |= MOD_BCLK_48FS;
92*4882a593Smuzhiyun break;
93*4882a593Smuzhiyun case 32:
94*4882a593Smuzhiyun mod |= MOD_BCLK_32FS;
95*4882a593Smuzhiyun break;
96*4882a593Smuzhiyun case 24:
97*4882a593Smuzhiyun mod |= MOD_BCLK_24FS;
98*4882a593Smuzhiyun break;
99*4882a593Smuzhiyun case 16:
100*4882a593Smuzhiyun mod |= MOD_BCLK_16FS;
101*4882a593Smuzhiyun break;
102*4882a593Smuzhiyun default:
103*4882a593Smuzhiyun return;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun writel(mod, &i2s_reg->mod);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /*
109*4882a593Smuzhiyun * flushes the i2stx fifo
110*4882a593Smuzhiyun *
111*4882a593Smuzhiyun * @param i2s_reg i2s regiter address
112*4882a593Smuzhiyun * @param flush Tx fifo flush command (0x00 - do not flush
113*4882a593Smuzhiyun * 0x80 - flush tx fifo)
114*4882a593Smuzhiyun */
i2s_fifo(struct i2s_reg * i2s_reg,unsigned int flush)115*4882a593Smuzhiyun void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun /* Flush the FIFO */
118*4882a593Smuzhiyun setbits_le32(&i2s_reg->fic, flush);
119*4882a593Smuzhiyun clrbits_le32(&i2s_reg->fic, flush);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun /*
123*4882a593Smuzhiyun * Set System Clock direction
124*4882a593Smuzhiyun *
125*4882a593Smuzhiyun * @param i2s_reg i2s regiter address
126*4882a593Smuzhiyun * @param dir Clock direction
127*4882a593Smuzhiyun *
128*4882a593Smuzhiyun * @return int value 0 for success, -1 in case of error
129*4882a593Smuzhiyun */
i2s_set_sysclk_dir(struct i2s_reg * i2s_reg,int dir)130*4882a593Smuzhiyun int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun unsigned int mod = readl(&i2s_reg->mod);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (dir == SND_SOC_CLOCK_IN)
135*4882a593Smuzhiyun mod |= MOD_CDCLKCON;
136*4882a593Smuzhiyun else
137*4882a593Smuzhiyun mod &= ~MOD_CDCLKCON;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun writel(mod, &i2s_reg->mod);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /*
145*4882a593Smuzhiyun * Sets I2S Clcok format
146*4882a593Smuzhiyun *
147*4882a593Smuzhiyun * @param fmt i2s clock properties
148*4882a593Smuzhiyun * @param i2s_reg i2s regiter address
149*4882a593Smuzhiyun *
150*4882a593Smuzhiyun * @return int value 0 for success, -1 in case of error
151*4882a593Smuzhiyun */
i2s_set_fmt(struct i2s_reg * i2s_reg,unsigned int fmt)152*4882a593Smuzhiyun int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun unsigned int mod = readl(&i2s_reg->mod);
155*4882a593Smuzhiyun unsigned int tmp = 0;
156*4882a593Smuzhiyun unsigned int ret = 0;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun /* Format is priority */
159*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
160*4882a593Smuzhiyun case SND_SOC_DAIFMT_RIGHT_J:
161*4882a593Smuzhiyun tmp |= MOD_LR_RLOW;
162*4882a593Smuzhiyun tmp |= MOD_SDF_MSB;
163*4882a593Smuzhiyun break;
164*4882a593Smuzhiyun case SND_SOC_DAIFMT_LEFT_J:
165*4882a593Smuzhiyun tmp |= MOD_LR_RLOW;
166*4882a593Smuzhiyun tmp |= MOD_SDF_LSB;
167*4882a593Smuzhiyun break;
168*4882a593Smuzhiyun case SND_SOC_DAIFMT_I2S:
169*4882a593Smuzhiyun tmp |= MOD_SDF_IIS;
170*4882a593Smuzhiyun break;
171*4882a593Smuzhiyun default:
172*4882a593Smuzhiyun debug("%s: Invalid format priority [0x%x]\n", __func__,
173*4882a593Smuzhiyun (fmt & SND_SOC_DAIFMT_FORMAT_MASK));
174*4882a593Smuzhiyun return -1;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun /*
178*4882a593Smuzhiyun * INV flag is relative to the FORMAT flag - if set it simply
179*4882a593Smuzhiyun * flips the polarity specified by the Standard
180*4882a593Smuzhiyun */
181*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
182*4882a593Smuzhiyun case SND_SOC_DAIFMT_NB_NF:
183*4882a593Smuzhiyun break;
184*4882a593Smuzhiyun case SND_SOC_DAIFMT_NB_IF:
185*4882a593Smuzhiyun if (tmp & MOD_LR_RLOW)
186*4882a593Smuzhiyun tmp &= ~MOD_LR_RLOW;
187*4882a593Smuzhiyun else
188*4882a593Smuzhiyun tmp |= MOD_LR_RLOW;
189*4882a593Smuzhiyun break;
190*4882a593Smuzhiyun default:
191*4882a593Smuzhiyun debug("%s: Invalid clock ploarity input [0x%x]\n", __func__,
192*4882a593Smuzhiyun (fmt & SND_SOC_DAIFMT_INV_MASK));
193*4882a593Smuzhiyun return -1;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
197*4882a593Smuzhiyun case SND_SOC_DAIFMT_CBS_CFS:
198*4882a593Smuzhiyun tmp |= MOD_SLAVE;
199*4882a593Smuzhiyun break;
200*4882a593Smuzhiyun case SND_SOC_DAIFMT_CBM_CFM:
201*4882a593Smuzhiyun /* Set default source clock in Master mode */
202*4882a593Smuzhiyun ret = i2s_set_sysclk_dir(i2s_reg, SND_SOC_CLOCK_OUT);
203*4882a593Smuzhiyun if (ret != 0) {
204*4882a593Smuzhiyun debug("%s:set i2s clock direction failed\n", __func__);
205*4882a593Smuzhiyun return -1;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun break;
208*4882a593Smuzhiyun default:
209*4882a593Smuzhiyun debug("%s: Invalid master selection [0x%x]\n", __func__,
210*4882a593Smuzhiyun (fmt & SND_SOC_DAIFMT_MASTER_MASK));
211*4882a593Smuzhiyun return -1;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
215*4882a593Smuzhiyun mod |= tmp;
216*4882a593Smuzhiyun writel(mod, &i2s_reg->mod);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun return 0;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /*
222*4882a593Smuzhiyun * Sets the sample width in bits
223*4882a593Smuzhiyun *
224*4882a593Smuzhiyun * @param blc samplewidth (size of sample in bits)
225*4882a593Smuzhiyun * @param i2s_reg i2s regiter address
226*4882a593Smuzhiyun *
227*4882a593Smuzhiyun * @return int value 0 for success, -1 in case of error
228*4882a593Smuzhiyun */
i2s_set_samplesize(struct i2s_reg * i2s_reg,unsigned int blc)229*4882a593Smuzhiyun int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun unsigned int mod = readl(&i2s_reg->mod);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun mod &= ~MOD_BLCP_MASK;
234*4882a593Smuzhiyun mod &= ~MOD_BLC_MASK;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun switch (blc) {
237*4882a593Smuzhiyun case 8:
238*4882a593Smuzhiyun mod |= MOD_BLCP_8BIT;
239*4882a593Smuzhiyun mod |= MOD_BLC_8BIT;
240*4882a593Smuzhiyun break;
241*4882a593Smuzhiyun case 16:
242*4882a593Smuzhiyun mod |= MOD_BLCP_16BIT;
243*4882a593Smuzhiyun mod |= MOD_BLC_16BIT;
244*4882a593Smuzhiyun break;
245*4882a593Smuzhiyun case 24:
246*4882a593Smuzhiyun mod |= MOD_BLCP_24BIT;
247*4882a593Smuzhiyun mod |= MOD_BLC_24BIT;
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun default:
250*4882a593Smuzhiyun debug("%s: Invalid sample size input [0x%x]\n",
251*4882a593Smuzhiyun __func__, blc);
252*4882a593Smuzhiyun return -1;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun writel(mod, &i2s_reg->mod);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun return 0;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
i2s_transfer_tx_data(struct i2stx_info * pi2s_tx,unsigned int * data,unsigned long data_size)259*4882a593Smuzhiyun int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data,
260*4882a593Smuzhiyun unsigned long data_size)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun int i;
263*4882a593Smuzhiyun int start;
264*4882a593Smuzhiyun struct i2s_reg *i2s_reg =
265*4882a593Smuzhiyun (struct i2s_reg *)pi2s_tx->base_address;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun if (data_size < FIFO_LENGTH) {
268*4882a593Smuzhiyun debug("%s : Invalid data size\n", __func__);
269*4882a593Smuzhiyun return -1; /* invalid pcm data size */
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /* fill the tx buffer before stating the tx transmit */
273*4882a593Smuzhiyun for (i = 0; i < FIFO_LENGTH; i++)
274*4882a593Smuzhiyun writel(*data++, &i2s_reg->txd);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun data_size -= FIFO_LENGTH;
277*4882a593Smuzhiyun i2s_txctrl(i2s_reg, I2S_TX_ON);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun while (data_size > 0) {
280*4882a593Smuzhiyun start = get_timer(0);
281*4882a593Smuzhiyun if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) {
282*4882a593Smuzhiyun writel(*data++, &i2s_reg->txd);
283*4882a593Smuzhiyun data_size--;
284*4882a593Smuzhiyun } else {
285*4882a593Smuzhiyun if (get_timer(start) > TIMEOUT_I2S_TX) {
286*4882a593Smuzhiyun i2s_txctrl(i2s_reg, I2S_TX_OFF);
287*4882a593Smuzhiyun debug("%s: I2S Transfer Timeout\n", __func__);
288*4882a593Smuzhiyun return -1;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun i2s_txctrl(i2s_reg, I2S_TX_OFF);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun return 0;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
i2s_tx_init(struct i2stx_info * pi2s_tx)297*4882a593Smuzhiyun int i2s_tx_init(struct i2stx_info *pi2s_tx)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun int ret;
300*4882a593Smuzhiyun struct i2s_reg *i2s_reg =
301*4882a593Smuzhiyun (struct i2s_reg *)pi2s_tx->base_address;
302*4882a593Smuzhiyun if (pi2s_tx->id == 0) {
303*4882a593Smuzhiyun /* Initialize GPIO for I2S-0 */
304*4882a593Smuzhiyun exynos_pinmux_config(PERIPH_ID_I2S0, 0);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun /* Set EPLL Clock */
307*4882a593Smuzhiyun ret = set_epll_clk(pi2s_tx->samplingrate * pi2s_tx->rfs * 4);
308*4882a593Smuzhiyun } else if (pi2s_tx->id == 1) {
309*4882a593Smuzhiyun /* Initialize GPIO for I2S-1 */
310*4882a593Smuzhiyun exynos_pinmux_config(PERIPH_ID_I2S1, 0);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun /* Set EPLL Clock */
313*4882a593Smuzhiyun ret = set_epll_clk(pi2s_tx->audio_pll_clk);
314*4882a593Smuzhiyun } else {
315*4882a593Smuzhiyun debug("%s: unsupported i2s-%d bus\n", __func__, pi2s_tx->id);
316*4882a593Smuzhiyun return -1;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (ret != 0) {
320*4882a593Smuzhiyun debug("%s: epll clock set rate failed\n", __func__);
321*4882a593Smuzhiyun return -1;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun /* Select Clk Source for Audio 0 or 1 */
325*4882a593Smuzhiyun ret = set_i2s_clk_source(pi2s_tx->id);
326*4882a593Smuzhiyun if (ret == -1) {
327*4882a593Smuzhiyun debug("%s: unsupported clock for i2s-%d\n", __func__,
328*4882a593Smuzhiyun pi2s_tx->id);
329*4882a593Smuzhiyun return -1;
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun if (pi2s_tx->id == 0) {
333*4882a593Smuzhiyun /*Reset the i2s module */
334*4882a593Smuzhiyun writel(CON_RESET, &i2s_reg->con);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun writel(MOD_OP_CLK | MOD_RCLKSRC, &i2s_reg->mod);
337*4882a593Smuzhiyun /* set i2s prescaler */
338*4882a593Smuzhiyun writel(PSREN | PSVAL, &i2s_reg->psr);
339*4882a593Smuzhiyun } else {
340*4882a593Smuzhiyun /* Set Prescaler to get MCLK */
341*4882a593Smuzhiyun ret = set_i2s_clk_prescaler(pi2s_tx->audio_pll_clk,
342*4882a593Smuzhiyun (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
343*4882a593Smuzhiyun pi2s_tx->id);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun if (ret == -1) {
346*4882a593Smuzhiyun debug("%s: unsupported prescalar for i2s-%d\n", __func__,
347*4882a593Smuzhiyun pi2s_tx->id);
348*4882a593Smuzhiyun return -1;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun /* Configure I2s format */
352*4882a593Smuzhiyun ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
353*4882a593Smuzhiyun SND_SOC_DAIFMT_CBM_CFM));
354*4882a593Smuzhiyun if (ret == 0) {
355*4882a593Smuzhiyun i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs);
356*4882a593Smuzhiyun ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);
357*4882a593Smuzhiyun if (ret != 0) {
358*4882a593Smuzhiyun debug("%s:set sample rate failed\n", __func__);
359*4882a593Smuzhiyun return -1;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun i2s_set_bitclk_framesize(i2s_reg, pi2s_tx->bfs);
363*4882a593Smuzhiyun /* disable i2s transfer flag and flush the fifo */
364*4882a593Smuzhiyun i2s_txctrl(i2s_reg, I2S_TX_OFF);
365*4882a593Smuzhiyun i2s_fifo(i2s_reg, FIC_TXFLUSH);
366*4882a593Smuzhiyun } else {
367*4882a593Smuzhiyun debug("%s: failed\n", __func__);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun return ret;
371*4882a593Smuzhiyun }
372