1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // ALSA SoC Audio Layer - Samsung I2S Controller driver
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (c) 2010 Samsung Electronics Co. Ltd.
6*4882a593Smuzhiyun // Jaswinder Singh <jassisinghbrar@gmail.com>
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <dt-bindings/sound/samsung-i2s.h>
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/clk.h>
12*4882a593Smuzhiyun #include <linux/clk-provider.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/of.h>
16*4882a593Smuzhiyun #include <linux/of_device.h>
17*4882a593Smuzhiyun #include <linux/of_gpio.h>
18*4882a593Smuzhiyun #include <linux/pm_runtime.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <sound/soc.h>
21*4882a593Smuzhiyun #include <sound/pcm_params.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include <linux/platform_data/asoc-s3c.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "dma.h"
26*4882a593Smuzhiyun #include "idma.h"
27*4882a593Smuzhiyun #include "i2s.h"
28*4882a593Smuzhiyun #include "i2s-regs.h"
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define SAMSUNG_I2S_ID_PRIMARY 1
33*4882a593Smuzhiyun #define SAMSUNG_I2S_ID_SECONDARY 2
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun struct samsung_i2s_variant_regs {
36*4882a593Smuzhiyun unsigned int bfs_off;
37*4882a593Smuzhiyun unsigned int rfs_off;
38*4882a593Smuzhiyun unsigned int sdf_off;
39*4882a593Smuzhiyun unsigned int txr_off;
40*4882a593Smuzhiyun unsigned int rclksrc_off;
41*4882a593Smuzhiyun unsigned int mss_off;
42*4882a593Smuzhiyun unsigned int cdclkcon_off;
43*4882a593Smuzhiyun unsigned int lrp_off;
44*4882a593Smuzhiyun unsigned int bfs_mask;
45*4882a593Smuzhiyun unsigned int rfs_mask;
46*4882a593Smuzhiyun unsigned int ftx0cnt_off;
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun struct samsung_i2s_dai_data {
50*4882a593Smuzhiyun u32 quirks;
51*4882a593Smuzhiyun unsigned int pcm_rates;
52*4882a593Smuzhiyun const struct samsung_i2s_variant_regs *i2s_variant_regs;
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun struct i2s_dai {
56*4882a593Smuzhiyun /* Platform device for this DAI */
57*4882a593Smuzhiyun struct platform_device *pdev;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* Frame clock */
60*4882a593Smuzhiyun unsigned frmclk;
61*4882a593Smuzhiyun /*
62*4882a593Smuzhiyun * Specifically requested RCLK, BCLK by machine driver.
63*4882a593Smuzhiyun * 0 indicates CPU driver is free to choose any value.
64*4882a593Smuzhiyun */
65*4882a593Smuzhiyun unsigned rfs, bfs;
66*4882a593Smuzhiyun /* Pointer to the Primary_Fifo if this is Sec_Fifo, NULL otherwise */
67*4882a593Smuzhiyun struct i2s_dai *pri_dai;
68*4882a593Smuzhiyun /* Pointer to the Secondary_Fifo if it has one, NULL otherwise */
69*4882a593Smuzhiyun struct i2s_dai *sec_dai;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun #define DAI_OPENED (1 << 0) /* DAI is opened */
72*4882a593Smuzhiyun #define DAI_MANAGER (1 << 1) /* DAI is the manager */
73*4882a593Smuzhiyun unsigned mode;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* Driver for this DAI */
76*4882a593Smuzhiyun struct snd_soc_dai_driver *drv;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* DMA parameters */
79*4882a593Smuzhiyun struct snd_dmaengine_dai_dma_data dma_playback;
80*4882a593Smuzhiyun struct snd_dmaengine_dai_dma_data dma_capture;
81*4882a593Smuzhiyun struct snd_dmaengine_dai_dma_data idma_playback;
82*4882a593Smuzhiyun dma_filter_fn filter;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun struct samsung_i2s_priv *priv;
85*4882a593Smuzhiyun };
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun struct samsung_i2s_priv {
88*4882a593Smuzhiyun struct platform_device *pdev;
89*4882a593Smuzhiyun struct platform_device *pdev_sec;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun /* Lock for cross interface checks */
92*4882a593Smuzhiyun spinlock_t pcm_lock;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /* CPU DAIs and their corresponding drivers */
95*4882a593Smuzhiyun struct i2s_dai *dai;
96*4882a593Smuzhiyun struct snd_soc_dai_driver *dai_drv;
97*4882a593Smuzhiyun int num_dais;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* The I2S controller's core clock */
100*4882a593Smuzhiyun struct clk *clk;
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /* Clock for generating I2S signals */
103*4882a593Smuzhiyun struct clk *op_clk;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* Rate of RCLK source clock */
106*4882a593Smuzhiyun unsigned long rclk_srcrate;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* Cache of selected I2S registers for system suspend */
109*4882a593Smuzhiyun u32 suspend_i2smod;
110*4882a593Smuzhiyun u32 suspend_i2scon;
111*4882a593Smuzhiyun u32 suspend_i2spsr;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun const struct samsung_i2s_variant_regs *variant_regs;
114*4882a593Smuzhiyun u32 quirks;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun /* The clock provider's data */
117*4882a593Smuzhiyun struct clk *clk_table[3];
118*4882a593Smuzhiyun struct clk_onecell_data clk_data;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /* Spinlock protecting member fields below */
121*4882a593Smuzhiyun spinlock_t lock;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /* Memory mapped SFR region */
124*4882a593Smuzhiyun void __iomem *addr;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /* A flag indicating the I2S slave mode operation */
127*4882a593Smuzhiyun bool slave_mode;
128*4882a593Smuzhiyun };
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* Returns true if this is the 'overlay' stereo DAI */
is_secondary(struct i2s_dai * i2s)131*4882a593Smuzhiyun static inline bool is_secondary(struct i2s_dai *i2s)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun return i2s->drv->id == SAMSUNG_I2S_ID_SECONDARY;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /* If this interface of the controller is transmitting data */
tx_active(struct i2s_dai * i2s)137*4882a593Smuzhiyun static inline bool tx_active(struct i2s_dai *i2s)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun u32 active;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (!i2s)
142*4882a593Smuzhiyun return false;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun active = readl(i2s->priv->addr + I2SCON);
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun if (is_secondary(i2s))
147*4882a593Smuzhiyun active &= CON_TXSDMA_ACTIVE;
148*4882a593Smuzhiyun else
149*4882a593Smuzhiyun active &= CON_TXDMA_ACTIVE;
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun return active ? true : false;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /* Return pointer to the other DAI */
get_other_dai(struct i2s_dai * i2s)155*4882a593Smuzhiyun static inline struct i2s_dai *get_other_dai(struct i2s_dai *i2s)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun return i2s->pri_dai ? : i2s->sec_dai;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* If the other interface of the controller is transmitting data */
other_tx_active(struct i2s_dai * i2s)161*4882a593Smuzhiyun static inline bool other_tx_active(struct i2s_dai *i2s)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun struct i2s_dai *other = get_other_dai(i2s);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun return tx_active(other);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /* If any interface of the controller is transmitting data */
any_tx_active(struct i2s_dai * i2s)169*4882a593Smuzhiyun static inline bool any_tx_active(struct i2s_dai *i2s)
170*4882a593Smuzhiyun {
171*4882a593Smuzhiyun return tx_active(i2s) || other_tx_active(i2s);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /* If this interface of the controller is receiving data */
rx_active(struct i2s_dai * i2s)175*4882a593Smuzhiyun static inline bool rx_active(struct i2s_dai *i2s)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun u32 active;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun if (!i2s)
180*4882a593Smuzhiyun return false;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun active = readl(i2s->priv->addr + I2SCON) & CON_RXDMA_ACTIVE;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun return active ? true : false;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /* If the other interface of the controller is receiving data */
other_rx_active(struct i2s_dai * i2s)188*4882a593Smuzhiyun static inline bool other_rx_active(struct i2s_dai *i2s)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun struct i2s_dai *other = get_other_dai(i2s);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun return rx_active(other);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun /* If any interface of the controller is receiving data */
any_rx_active(struct i2s_dai * i2s)196*4882a593Smuzhiyun static inline bool any_rx_active(struct i2s_dai *i2s)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun return rx_active(i2s) || other_rx_active(i2s);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun /* If the other DAI is transmitting or receiving data */
other_active(struct i2s_dai * i2s)202*4882a593Smuzhiyun static inline bool other_active(struct i2s_dai *i2s)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun return other_rx_active(i2s) || other_tx_active(i2s);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* If this DAI is transmitting or receiving data */
this_active(struct i2s_dai * i2s)208*4882a593Smuzhiyun static inline bool this_active(struct i2s_dai *i2s)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun return tx_active(i2s) || rx_active(i2s);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* If the controller is active anyway */
any_active(struct i2s_dai * i2s)214*4882a593Smuzhiyun static inline bool any_active(struct i2s_dai *i2s)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun return this_active(i2s) || other_active(i2s);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
to_info(struct snd_soc_dai * dai)219*4882a593Smuzhiyun static inline struct i2s_dai *to_info(struct snd_soc_dai *dai)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun return &priv->dai[dai->id - 1];
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
is_opened(struct i2s_dai * i2s)226*4882a593Smuzhiyun static inline bool is_opened(struct i2s_dai *i2s)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun if (i2s && (i2s->mode & DAI_OPENED))
229*4882a593Smuzhiyun return true;
230*4882a593Smuzhiyun else
231*4882a593Smuzhiyun return false;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
is_manager(struct i2s_dai * i2s)234*4882a593Smuzhiyun static inline bool is_manager(struct i2s_dai *i2s)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun if (is_opened(i2s) && (i2s->mode & DAI_MANAGER))
237*4882a593Smuzhiyun return true;
238*4882a593Smuzhiyun else
239*4882a593Smuzhiyun return false;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* Read RCLK of I2S (in multiples of LRCLK) */
get_rfs(struct i2s_dai * i2s)243*4882a593Smuzhiyun static inline unsigned get_rfs(struct i2s_dai *i2s)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun struct samsung_i2s_priv *priv = i2s->priv;
246*4882a593Smuzhiyun u32 rfs;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun rfs = readl(priv->addr + I2SMOD) >> priv->variant_regs->rfs_off;
249*4882a593Smuzhiyun rfs &= priv->variant_regs->rfs_mask;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun switch (rfs) {
252*4882a593Smuzhiyun case 7: return 192;
253*4882a593Smuzhiyun case 6: return 96;
254*4882a593Smuzhiyun case 5: return 128;
255*4882a593Smuzhiyun case 4: return 64;
256*4882a593Smuzhiyun case 3: return 768;
257*4882a593Smuzhiyun case 2: return 384;
258*4882a593Smuzhiyun case 1: return 512;
259*4882a593Smuzhiyun default: return 256;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /* Write RCLK of I2S (in multiples of LRCLK) */
set_rfs(struct i2s_dai * i2s,unsigned rfs)264*4882a593Smuzhiyun static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun struct samsung_i2s_priv *priv = i2s->priv;
267*4882a593Smuzhiyun u32 mod = readl(priv->addr + I2SMOD);
268*4882a593Smuzhiyun int rfs_shift = priv->variant_regs->rfs_off;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun mod &= ~(priv->variant_regs->rfs_mask << rfs_shift);
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun switch (rfs) {
273*4882a593Smuzhiyun case 192:
274*4882a593Smuzhiyun mod |= (EXYNOS7_MOD_RCLK_192FS << rfs_shift);
275*4882a593Smuzhiyun break;
276*4882a593Smuzhiyun case 96:
277*4882a593Smuzhiyun mod |= (EXYNOS7_MOD_RCLK_96FS << rfs_shift);
278*4882a593Smuzhiyun break;
279*4882a593Smuzhiyun case 128:
280*4882a593Smuzhiyun mod |= (EXYNOS7_MOD_RCLK_128FS << rfs_shift);
281*4882a593Smuzhiyun break;
282*4882a593Smuzhiyun case 64:
283*4882a593Smuzhiyun mod |= (EXYNOS7_MOD_RCLK_64FS << rfs_shift);
284*4882a593Smuzhiyun break;
285*4882a593Smuzhiyun case 768:
286*4882a593Smuzhiyun mod |= (MOD_RCLK_768FS << rfs_shift);
287*4882a593Smuzhiyun break;
288*4882a593Smuzhiyun case 512:
289*4882a593Smuzhiyun mod |= (MOD_RCLK_512FS << rfs_shift);
290*4882a593Smuzhiyun break;
291*4882a593Smuzhiyun case 384:
292*4882a593Smuzhiyun mod |= (MOD_RCLK_384FS << rfs_shift);
293*4882a593Smuzhiyun break;
294*4882a593Smuzhiyun default:
295*4882a593Smuzhiyun mod |= (MOD_RCLK_256FS << rfs_shift);
296*4882a593Smuzhiyun break;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun writel(mod, priv->addr + I2SMOD);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* Read bit-clock of I2S (in multiples of LRCLK) */
get_bfs(struct i2s_dai * i2s)303*4882a593Smuzhiyun static inline unsigned get_bfs(struct i2s_dai *i2s)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun struct samsung_i2s_priv *priv = i2s->priv;
306*4882a593Smuzhiyun u32 bfs;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun bfs = readl(priv->addr + I2SMOD) >> priv->variant_regs->bfs_off;
309*4882a593Smuzhiyun bfs &= priv->variant_regs->bfs_mask;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun switch (bfs) {
312*4882a593Smuzhiyun case 8: return 256;
313*4882a593Smuzhiyun case 7: return 192;
314*4882a593Smuzhiyun case 6: return 128;
315*4882a593Smuzhiyun case 5: return 96;
316*4882a593Smuzhiyun case 4: return 64;
317*4882a593Smuzhiyun case 3: return 24;
318*4882a593Smuzhiyun case 2: return 16;
319*4882a593Smuzhiyun case 1: return 48;
320*4882a593Smuzhiyun default: return 32;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun /* Write bit-clock of I2S (in multiples of LRCLK) */
set_bfs(struct i2s_dai * i2s,unsigned bfs)325*4882a593Smuzhiyun static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun struct samsung_i2s_priv *priv = i2s->priv;
328*4882a593Smuzhiyun u32 mod = readl(priv->addr + I2SMOD);
329*4882a593Smuzhiyun int tdm = priv->quirks & QUIRK_SUPPORTS_TDM;
330*4882a593Smuzhiyun int bfs_shift = priv->variant_regs->bfs_off;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun /* Non-TDM I2S controllers do not support BCLK > 48 * FS */
333*4882a593Smuzhiyun if (!tdm && bfs > 48) {
334*4882a593Smuzhiyun dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n");
335*4882a593Smuzhiyun return;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun mod &= ~(priv->variant_regs->bfs_mask << bfs_shift);
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun switch (bfs) {
341*4882a593Smuzhiyun case 48:
342*4882a593Smuzhiyun mod |= (MOD_BCLK_48FS << bfs_shift);
343*4882a593Smuzhiyun break;
344*4882a593Smuzhiyun case 32:
345*4882a593Smuzhiyun mod |= (MOD_BCLK_32FS << bfs_shift);
346*4882a593Smuzhiyun break;
347*4882a593Smuzhiyun case 24:
348*4882a593Smuzhiyun mod |= (MOD_BCLK_24FS << bfs_shift);
349*4882a593Smuzhiyun break;
350*4882a593Smuzhiyun case 16:
351*4882a593Smuzhiyun mod |= (MOD_BCLK_16FS << bfs_shift);
352*4882a593Smuzhiyun break;
353*4882a593Smuzhiyun case 64:
354*4882a593Smuzhiyun mod |= (EXYNOS5420_MOD_BCLK_64FS << bfs_shift);
355*4882a593Smuzhiyun break;
356*4882a593Smuzhiyun case 96:
357*4882a593Smuzhiyun mod |= (EXYNOS5420_MOD_BCLK_96FS << bfs_shift);
358*4882a593Smuzhiyun break;
359*4882a593Smuzhiyun case 128:
360*4882a593Smuzhiyun mod |= (EXYNOS5420_MOD_BCLK_128FS << bfs_shift);
361*4882a593Smuzhiyun break;
362*4882a593Smuzhiyun case 192:
363*4882a593Smuzhiyun mod |= (EXYNOS5420_MOD_BCLK_192FS << bfs_shift);
364*4882a593Smuzhiyun break;
365*4882a593Smuzhiyun case 256:
366*4882a593Smuzhiyun mod |= (EXYNOS5420_MOD_BCLK_256FS << bfs_shift);
367*4882a593Smuzhiyun break;
368*4882a593Smuzhiyun default:
369*4882a593Smuzhiyun dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n");
370*4882a593Smuzhiyun return;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun writel(mod, priv->addr + I2SMOD);
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun /* Sample size */
get_blc(struct i2s_dai * i2s)377*4882a593Smuzhiyun static inline int get_blc(struct i2s_dai *i2s)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun int blc = readl(i2s->priv->addr + I2SMOD);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun blc = (blc >> 13) & 0x3;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun switch (blc) {
384*4882a593Smuzhiyun case 2: return 24;
385*4882a593Smuzhiyun case 1: return 8;
386*4882a593Smuzhiyun default: return 16;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun /* TX channel control */
i2s_txctrl(struct i2s_dai * i2s,int on)391*4882a593Smuzhiyun static void i2s_txctrl(struct i2s_dai *i2s, int on)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun struct samsung_i2s_priv *priv = i2s->priv;
394*4882a593Smuzhiyun void __iomem *addr = priv->addr;
395*4882a593Smuzhiyun int txr_off = priv->variant_regs->txr_off;
396*4882a593Smuzhiyun u32 con = readl(addr + I2SCON);
397*4882a593Smuzhiyun u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun if (on) {
400*4882a593Smuzhiyun con |= CON_ACTIVE;
401*4882a593Smuzhiyun con &= ~CON_TXCH_PAUSE;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun if (is_secondary(i2s)) {
404*4882a593Smuzhiyun con |= CON_TXSDMA_ACTIVE;
405*4882a593Smuzhiyun con &= ~CON_TXSDMA_PAUSE;
406*4882a593Smuzhiyun } else {
407*4882a593Smuzhiyun con |= CON_TXDMA_ACTIVE;
408*4882a593Smuzhiyun con &= ~CON_TXDMA_PAUSE;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun if (any_rx_active(i2s))
412*4882a593Smuzhiyun mod |= 2 << txr_off;
413*4882a593Smuzhiyun else
414*4882a593Smuzhiyun mod |= 0 << txr_off;
415*4882a593Smuzhiyun } else {
416*4882a593Smuzhiyun if (is_secondary(i2s)) {
417*4882a593Smuzhiyun con |= CON_TXSDMA_PAUSE;
418*4882a593Smuzhiyun con &= ~CON_TXSDMA_ACTIVE;
419*4882a593Smuzhiyun } else {
420*4882a593Smuzhiyun con |= CON_TXDMA_PAUSE;
421*4882a593Smuzhiyun con &= ~CON_TXDMA_ACTIVE;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun if (other_tx_active(i2s)) {
425*4882a593Smuzhiyun writel(con, addr + I2SCON);
426*4882a593Smuzhiyun return;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun con |= CON_TXCH_PAUSE;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if (any_rx_active(i2s))
432*4882a593Smuzhiyun mod |= 1 << txr_off;
433*4882a593Smuzhiyun else
434*4882a593Smuzhiyun con &= ~CON_ACTIVE;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun writel(mod, addr + I2SMOD);
438*4882a593Smuzhiyun writel(con, addr + I2SCON);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /* RX Channel Control */
i2s_rxctrl(struct i2s_dai * i2s,int on)442*4882a593Smuzhiyun static void i2s_rxctrl(struct i2s_dai *i2s, int on)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun struct samsung_i2s_priv *priv = i2s->priv;
445*4882a593Smuzhiyun void __iomem *addr = priv->addr;
446*4882a593Smuzhiyun int txr_off = priv->variant_regs->txr_off;
447*4882a593Smuzhiyun u32 con = readl(addr + I2SCON);
448*4882a593Smuzhiyun u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if (on) {
451*4882a593Smuzhiyun con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
452*4882a593Smuzhiyun con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun if (any_tx_active(i2s))
455*4882a593Smuzhiyun mod |= 2 << txr_off;
456*4882a593Smuzhiyun else
457*4882a593Smuzhiyun mod |= 1 << txr_off;
458*4882a593Smuzhiyun } else {
459*4882a593Smuzhiyun con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
460*4882a593Smuzhiyun con &= ~CON_RXDMA_ACTIVE;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun if (any_tx_active(i2s))
463*4882a593Smuzhiyun mod |= 0 << txr_off;
464*4882a593Smuzhiyun else
465*4882a593Smuzhiyun con &= ~CON_ACTIVE;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun writel(mod, addr + I2SMOD);
469*4882a593Smuzhiyun writel(con, addr + I2SCON);
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun /* Flush FIFO of an interface */
i2s_fifo(struct i2s_dai * i2s,u32 flush)473*4882a593Smuzhiyun static inline void i2s_fifo(struct i2s_dai *i2s, u32 flush)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun void __iomem *fic;
476*4882a593Smuzhiyun u32 val;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun if (!i2s)
479*4882a593Smuzhiyun return;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun if (is_secondary(i2s))
482*4882a593Smuzhiyun fic = i2s->priv->addr + I2SFICS;
483*4882a593Smuzhiyun else
484*4882a593Smuzhiyun fic = i2s->priv->addr + I2SFIC;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun /* Flush the FIFO */
487*4882a593Smuzhiyun writel(readl(fic) | flush, fic);
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun /* Be patient */
490*4882a593Smuzhiyun val = msecs_to_loops(1) / 1000; /* 1 usec */
491*4882a593Smuzhiyun while (--val)
492*4882a593Smuzhiyun cpu_relax();
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun writel(readl(fic) & ~flush, fic);
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
i2s_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int rfs,int dir)497*4882a593Smuzhiyun static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs,
498*4882a593Smuzhiyun int dir)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
501*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(dai);
502*4882a593Smuzhiyun struct i2s_dai *other = get_other_dai(i2s);
503*4882a593Smuzhiyun const struct samsung_i2s_variant_regs *i2s_regs = priv->variant_regs;
504*4882a593Smuzhiyun unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
505*4882a593Smuzhiyun unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
506*4882a593Smuzhiyun u32 mod, mask, val = 0;
507*4882a593Smuzhiyun unsigned long flags;
508*4882a593Smuzhiyun int ret = 0;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun pm_runtime_get_sync(dai->dev);
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
513*4882a593Smuzhiyun mod = readl(priv->addr + I2SMOD);
514*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun switch (clk_id) {
517*4882a593Smuzhiyun case SAMSUNG_I2S_OPCLK:
518*4882a593Smuzhiyun mask = MOD_OPCLK_MASK;
519*4882a593Smuzhiyun val = (dir << MOD_OPCLK_SHIFT) & MOD_OPCLK_MASK;
520*4882a593Smuzhiyun break;
521*4882a593Smuzhiyun case SAMSUNG_I2S_CDCLK:
522*4882a593Smuzhiyun mask = 1 << i2s_regs->cdclkcon_off;
523*4882a593Smuzhiyun /* Shouldn't matter in GATING(CLOCK_IN) mode */
524*4882a593Smuzhiyun if (dir == SND_SOC_CLOCK_IN)
525*4882a593Smuzhiyun rfs = 0;
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if ((rfs && other && other->rfs && (other->rfs != rfs)) ||
528*4882a593Smuzhiyun (any_active(i2s) &&
529*4882a593Smuzhiyun (((dir == SND_SOC_CLOCK_IN)
530*4882a593Smuzhiyun && !(mod & cdcon_mask)) ||
531*4882a593Smuzhiyun ((dir == SND_SOC_CLOCK_OUT)
532*4882a593Smuzhiyun && (mod & cdcon_mask))))) {
533*4882a593Smuzhiyun dev_err(&i2s->pdev->dev,
534*4882a593Smuzhiyun "%s:%d Other DAI busy\n", __func__, __LINE__);
535*4882a593Smuzhiyun ret = -EAGAIN;
536*4882a593Smuzhiyun goto err;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun if (dir == SND_SOC_CLOCK_IN)
540*4882a593Smuzhiyun val = 1 << i2s_regs->cdclkcon_off;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun i2s->rfs = rfs;
543*4882a593Smuzhiyun break;
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
546*4882a593Smuzhiyun case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
547*4882a593Smuzhiyun mask = 1 << i2s_regs->rclksrc_off;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if ((priv->quirks & QUIRK_NO_MUXPSR)
550*4882a593Smuzhiyun || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
551*4882a593Smuzhiyun clk_id = 0;
552*4882a593Smuzhiyun else
553*4882a593Smuzhiyun clk_id = 1;
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun if (!any_active(i2s)) {
556*4882a593Smuzhiyun if (priv->op_clk && !IS_ERR(priv->op_clk)) {
557*4882a593Smuzhiyun if ((clk_id && !(mod & rsrc_mask)) ||
558*4882a593Smuzhiyun (!clk_id && (mod & rsrc_mask))) {
559*4882a593Smuzhiyun clk_disable_unprepare(priv->op_clk);
560*4882a593Smuzhiyun clk_put(priv->op_clk);
561*4882a593Smuzhiyun } else {
562*4882a593Smuzhiyun priv->rclk_srcrate =
563*4882a593Smuzhiyun clk_get_rate(priv->op_clk);
564*4882a593Smuzhiyun goto done;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (clk_id)
569*4882a593Smuzhiyun priv->op_clk = clk_get(&i2s->pdev->dev,
570*4882a593Smuzhiyun "i2s_opclk1");
571*4882a593Smuzhiyun else
572*4882a593Smuzhiyun priv->op_clk = clk_get(&i2s->pdev->dev,
573*4882a593Smuzhiyun "i2s_opclk0");
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun if (WARN_ON(IS_ERR(priv->op_clk))) {
576*4882a593Smuzhiyun ret = PTR_ERR(priv->op_clk);
577*4882a593Smuzhiyun priv->op_clk = NULL;
578*4882a593Smuzhiyun goto err;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun ret = clk_prepare_enable(priv->op_clk);
582*4882a593Smuzhiyun if (ret) {
583*4882a593Smuzhiyun clk_put(priv->op_clk);
584*4882a593Smuzhiyun priv->op_clk = NULL;
585*4882a593Smuzhiyun goto err;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun priv->rclk_srcrate = clk_get_rate(priv->op_clk);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun } else if ((!clk_id && (mod & rsrc_mask))
590*4882a593Smuzhiyun || (clk_id && !(mod & rsrc_mask))) {
591*4882a593Smuzhiyun dev_err(&i2s->pdev->dev,
592*4882a593Smuzhiyun "%s:%d Other DAI busy\n", __func__, __LINE__);
593*4882a593Smuzhiyun ret = -EAGAIN;
594*4882a593Smuzhiyun goto err;
595*4882a593Smuzhiyun } else {
596*4882a593Smuzhiyun /* Call can't be on the active DAI */
597*4882a593Smuzhiyun goto done;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun if (clk_id == 1)
601*4882a593Smuzhiyun val = 1 << i2s_regs->rclksrc_off;
602*4882a593Smuzhiyun break;
603*4882a593Smuzhiyun default:
604*4882a593Smuzhiyun dev_err(&i2s->pdev->dev, "We don't serve that!\n");
605*4882a593Smuzhiyun ret = -EINVAL;
606*4882a593Smuzhiyun goto err;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
610*4882a593Smuzhiyun mod = readl(priv->addr + I2SMOD);
611*4882a593Smuzhiyun mod = (mod & ~mask) | val;
612*4882a593Smuzhiyun writel(mod, priv->addr + I2SMOD);
613*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
614*4882a593Smuzhiyun done:
615*4882a593Smuzhiyun pm_runtime_put(dai->dev);
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun return 0;
618*4882a593Smuzhiyun err:
619*4882a593Smuzhiyun pm_runtime_put(dai->dev);
620*4882a593Smuzhiyun return ret;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
i2s_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)623*4882a593Smuzhiyun static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
626*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(dai);
627*4882a593Smuzhiyun int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
628*4882a593Smuzhiyun u32 mod, tmp = 0;
629*4882a593Smuzhiyun unsigned long flags;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun lrp_shift = priv->variant_regs->lrp_off;
632*4882a593Smuzhiyun sdf_shift = priv->variant_regs->sdf_off;
633*4882a593Smuzhiyun mod_slave = 1 << priv->variant_regs->mss_off;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun sdf_mask = MOD_SDF_MASK << sdf_shift;
636*4882a593Smuzhiyun lrp_rlow = MOD_LR_RLOW << lrp_shift;
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun /* Format is priority */
639*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
640*4882a593Smuzhiyun case SND_SOC_DAIFMT_RIGHT_J:
641*4882a593Smuzhiyun tmp |= lrp_rlow;
642*4882a593Smuzhiyun tmp |= (MOD_SDF_MSB << sdf_shift);
643*4882a593Smuzhiyun break;
644*4882a593Smuzhiyun case SND_SOC_DAIFMT_LEFT_J:
645*4882a593Smuzhiyun tmp |= lrp_rlow;
646*4882a593Smuzhiyun tmp |= (MOD_SDF_LSB << sdf_shift);
647*4882a593Smuzhiyun break;
648*4882a593Smuzhiyun case SND_SOC_DAIFMT_I2S:
649*4882a593Smuzhiyun tmp |= (MOD_SDF_IIS << sdf_shift);
650*4882a593Smuzhiyun break;
651*4882a593Smuzhiyun default:
652*4882a593Smuzhiyun dev_err(&i2s->pdev->dev, "Format not supported\n");
653*4882a593Smuzhiyun return -EINVAL;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun /*
657*4882a593Smuzhiyun * INV flag is relative to the FORMAT flag - if set it simply
658*4882a593Smuzhiyun * flips the polarity specified by the Standard
659*4882a593Smuzhiyun */
660*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
661*4882a593Smuzhiyun case SND_SOC_DAIFMT_NB_NF:
662*4882a593Smuzhiyun break;
663*4882a593Smuzhiyun case SND_SOC_DAIFMT_NB_IF:
664*4882a593Smuzhiyun if (tmp & lrp_rlow)
665*4882a593Smuzhiyun tmp &= ~lrp_rlow;
666*4882a593Smuzhiyun else
667*4882a593Smuzhiyun tmp |= lrp_rlow;
668*4882a593Smuzhiyun break;
669*4882a593Smuzhiyun default:
670*4882a593Smuzhiyun dev_err(&i2s->pdev->dev, "Polarity not supported\n");
671*4882a593Smuzhiyun return -EINVAL;
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
675*4882a593Smuzhiyun case SND_SOC_DAIFMT_CBM_CFM:
676*4882a593Smuzhiyun tmp |= mod_slave;
677*4882a593Smuzhiyun break;
678*4882a593Smuzhiyun case SND_SOC_DAIFMT_CBS_CFS:
679*4882a593Smuzhiyun /*
680*4882a593Smuzhiyun * Set default source clock in Master mode, only when the
681*4882a593Smuzhiyun * CLK_I2S_RCLK_SRC clock is not exposed so we ensure any
682*4882a593Smuzhiyun * clock configuration assigned in DT is not overwritten.
683*4882a593Smuzhiyun */
684*4882a593Smuzhiyun if (priv->rclk_srcrate == 0 && priv->clk_data.clks == NULL)
685*4882a593Smuzhiyun i2s_set_sysclk(dai, SAMSUNG_I2S_RCLKSRC_0,
686*4882a593Smuzhiyun 0, SND_SOC_CLOCK_IN);
687*4882a593Smuzhiyun break;
688*4882a593Smuzhiyun default:
689*4882a593Smuzhiyun dev_err(&i2s->pdev->dev, "master/slave format not supported\n");
690*4882a593Smuzhiyun return -EINVAL;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun pm_runtime_get_sync(dai->dev);
694*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
695*4882a593Smuzhiyun mod = readl(priv->addr + I2SMOD);
696*4882a593Smuzhiyun /*
697*4882a593Smuzhiyun * Don't change the I2S mode if any controller is active on this
698*4882a593Smuzhiyun * channel.
699*4882a593Smuzhiyun */
700*4882a593Smuzhiyun if (any_active(i2s) &&
701*4882a593Smuzhiyun ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
702*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
703*4882a593Smuzhiyun pm_runtime_put(dai->dev);
704*4882a593Smuzhiyun dev_err(&i2s->pdev->dev,
705*4882a593Smuzhiyun "%s:%d Other DAI busy\n", __func__, __LINE__);
706*4882a593Smuzhiyun return -EAGAIN;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun mod &= ~(sdf_mask | lrp_rlow | mod_slave);
710*4882a593Smuzhiyun mod |= tmp;
711*4882a593Smuzhiyun writel(mod, priv->addr + I2SMOD);
712*4882a593Smuzhiyun priv->slave_mode = (mod & mod_slave);
713*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
714*4882a593Smuzhiyun pm_runtime_put(dai->dev);
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun return 0;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
i2s_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)719*4882a593Smuzhiyun static int i2s_hw_params(struct snd_pcm_substream *substream,
720*4882a593Smuzhiyun struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
723*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(dai);
724*4882a593Smuzhiyun u32 mod, mask = 0, val = 0;
725*4882a593Smuzhiyun struct clk *rclksrc;
726*4882a593Smuzhiyun unsigned long flags;
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun WARN_ON(!pm_runtime_active(dai->dev));
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun if (!is_secondary(i2s))
731*4882a593Smuzhiyun mask |= (MOD_DC2_EN | MOD_DC1_EN);
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun switch (params_channels(params)) {
734*4882a593Smuzhiyun case 6:
735*4882a593Smuzhiyun val |= MOD_DC2_EN;
736*4882a593Smuzhiyun fallthrough;
737*4882a593Smuzhiyun case 4:
738*4882a593Smuzhiyun val |= MOD_DC1_EN;
739*4882a593Smuzhiyun break;
740*4882a593Smuzhiyun case 2:
741*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
742*4882a593Smuzhiyun i2s->dma_playback.addr_width = 4;
743*4882a593Smuzhiyun else
744*4882a593Smuzhiyun i2s->dma_capture.addr_width = 4;
745*4882a593Smuzhiyun break;
746*4882a593Smuzhiyun case 1:
747*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
748*4882a593Smuzhiyun i2s->dma_playback.addr_width = 2;
749*4882a593Smuzhiyun else
750*4882a593Smuzhiyun i2s->dma_capture.addr_width = 2;
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun break;
753*4882a593Smuzhiyun default:
754*4882a593Smuzhiyun dev_err(&i2s->pdev->dev, "%d channels not supported\n",
755*4882a593Smuzhiyun params_channels(params));
756*4882a593Smuzhiyun return -EINVAL;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun if (is_secondary(i2s))
760*4882a593Smuzhiyun mask |= MOD_BLCS_MASK;
761*4882a593Smuzhiyun else
762*4882a593Smuzhiyun mask |= MOD_BLCP_MASK;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun if (is_manager(i2s))
765*4882a593Smuzhiyun mask |= MOD_BLC_MASK;
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun switch (params_width(params)) {
768*4882a593Smuzhiyun case 8:
769*4882a593Smuzhiyun if (is_secondary(i2s))
770*4882a593Smuzhiyun val |= MOD_BLCS_8BIT;
771*4882a593Smuzhiyun else
772*4882a593Smuzhiyun val |= MOD_BLCP_8BIT;
773*4882a593Smuzhiyun if (is_manager(i2s))
774*4882a593Smuzhiyun val |= MOD_BLC_8BIT;
775*4882a593Smuzhiyun break;
776*4882a593Smuzhiyun case 16:
777*4882a593Smuzhiyun if (is_secondary(i2s))
778*4882a593Smuzhiyun val |= MOD_BLCS_16BIT;
779*4882a593Smuzhiyun else
780*4882a593Smuzhiyun val |= MOD_BLCP_16BIT;
781*4882a593Smuzhiyun if (is_manager(i2s))
782*4882a593Smuzhiyun val |= MOD_BLC_16BIT;
783*4882a593Smuzhiyun break;
784*4882a593Smuzhiyun case 24:
785*4882a593Smuzhiyun if (is_secondary(i2s))
786*4882a593Smuzhiyun val |= MOD_BLCS_24BIT;
787*4882a593Smuzhiyun else
788*4882a593Smuzhiyun val |= MOD_BLCP_24BIT;
789*4882a593Smuzhiyun if (is_manager(i2s))
790*4882a593Smuzhiyun val |= MOD_BLC_24BIT;
791*4882a593Smuzhiyun break;
792*4882a593Smuzhiyun default:
793*4882a593Smuzhiyun dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
794*4882a593Smuzhiyun params_format(params));
795*4882a593Smuzhiyun return -EINVAL;
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
799*4882a593Smuzhiyun mod = readl(priv->addr + I2SMOD);
800*4882a593Smuzhiyun mod = (mod & ~mask) | val;
801*4882a593Smuzhiyun writel(mod, priv->addr + I2SMOD);
802*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun i2s->frmclk = params_rate(params);
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun rclksrc = priv->clk_table[CLK_I2S_RCLK_SRC];
809*4882a593Smuzhiyun if (rclksrc && !IS_ERR(rclksrc))
810*4882a593Smuzhiyun priv->rclk_srcrate = clk_get_rate(rclksrc);
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun return 0;
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun /* We set constraints on the substream according to the version of I2S */
i2s_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)816*4882a593Smuzhiyun static int i2s_startup(struct snd_pcm_substream *substream,
817*4882a593Smuzhiyun struct snd_soc_dai *dai)
818*4882a593Smuzhiyun {
819*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
820*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(dai);
821*4882a593Smuzhiyun struct i2s_dai *other = get_other_dai(i2s);
822*4882a593Smuzhiyun unsigned long flags;
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun pm_runtime_get_sync(dai->dev);
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun spin_lock_irqsave(&priv->pcm_lock, flags);
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun i2s->mode |= DAI_OPENED;
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun if (is_manager(other))
831*4882a593Smuzhiyun i2s->mode &= ~DAI_MANAGER;
832*4882a593Smuzhiyun else
833*4882a593Smuzhiyun i2s->mode |= DAI_MANAGER;
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun if (!any_active(i2s) && (priv->quirks & QUIRK_NEED_RSTCLR))
836*4882a593Smuzhiyun writel(CON_RSTCLR, i2s->priv->addr + I2SCON);
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->pcm_lock, flags);
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun return 0;
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun
i2s_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)843*4882a593Smuzhiyun static void i2s_shutdown(struct snd_pcm_substream *substream,
844*4882a593Smuzhiyun struct snd_soc_dai *dai)
845*4882a593Smuzhiyun {
846*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
847*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(dai);
848*4882a593Smuzhiyun struct i2s_dai *other = get_other_dai(i2s);
849*4882a593Smuzhiyun unsigned long flags;
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun spin_lock_irqsave(&priv->pcm_lock, flags);
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun i2s->mode &= ~DAI_OPENED;
854*4882a593Smuzhiyun i2s->mode &= ~DAI_MANAGER;
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun if (is_opened(other))
857*4882a593Smuzhiyun other->mode |= DAI_MANAGER;
858*4882a593Smuzhiyun
859*4882a593Smuzhiyun /* Reset any constraint on RFS and BFS */
860*4882a593Smuzhiyun i2s->rfs = 0;
861*4882a593Smuzhiyun i2s->bfs = 0;
862*4882a593Smuzhiyun
863*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->pcm_lock, flags);
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun pm_runtime_put(dai->dev);
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
config_setup(struct i2s_dai * i2s)868*4882a593Smuzhiyun static int config_setup(struct i2s_dai *i2s)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun struct samsung_i2s_priv *priv = i2s->priv;
871*4882a593Smuzhiyun struct i2s_dai *other = get_other_dai(i2s);
872*4882a593Smuzhiyun unsigned rfs, bfs, blc;
873*4882a593Smuzhiyun u32 psr;
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun blc = get_blc(i2s);
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun bfs = i2s->bfs;
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun if (!bfs && other)
880*4882a593Smuzhiyun bfs = other->bfs;
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun /* Select least possible multiple(2) if no constraint set */
883*4882a593Smuzhiyun if (!bfs)
884*4882a593Smuzhiyun bfs = blc * 2;
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun rfs = i2s->rfs;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun if (!rfs && other)
889*4882a593Smuzhiyun rfs = other->rfs;
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun if ((rfs == 256 || rfs == 512) && (blc == 24)) {
892*4882a593Smuzhiyun dev_err(&i2s->pdev->dev,
893*4882a593Smuzhiyun "%d-RFS not supported for 24-blc\n", rfs);
894*4882a593Smuzhiyun return -EINVAL;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun if (!rfs) {
898*4882a593Smuzhiyun if (bfs == 16 || bfs == 32)
899*4882a593Smuzhiyun rfs = 256;
900*4882a593Smuzhiyun else
901*4882a593Smuzhiyun rfs = 384;
902*4882a593Smuzhiyun }
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun /* If already setup and running */
905*4882a593Smuzhiyun if (any_active(i2s) && (get_rfs(i2s) != rfs || get_bfs(i2s) != bfs)) {
906*4882a593Smuzhiyun dev_err(&i2s->pdev->dev,
907*4882a593Smuzhiyun "%s:%d Other DAI busy\n", __func__, __LINE__);
908*4882a593Smuzhiyun return -EAGAIN;
909*4882a593Smuzhiyun }
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun set_bfs(i2s, bfs);
912*4882a593Smuzhiyun set_rfs(i2s, rfs);
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun /* Don't bother with PSR in Slave mode */
915*4882a593Smuzhiyun if (priv->slave_mode)
916*4882a593Smuzhiyun return 0;
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun if (!(priv->quirks & QUIRK_NO_MUXPSR)) {
919*4882a593Smuzhiyun psr = priv->rclk_srcrate / i2s->frmclk / rfs;
920*4882a593Smuzhiyun writel(((psr - 1) << 8) | PSR_PSREN, priv->addr + I2SPSR);
921*4882a593Smuzhiyun dev_dbg(&i2s->pdev->dev,
922*4882a593Smuzhiyun "RCLK_SRC=%luHz PSR=%u, RCLK=%dfs, BCLK=%dfs\n",
923*4882a593Smuzhiyun priv->rclk_srcrate, psr, rfs, bfs);
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun return 0;
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun
i2s_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)929*4882a593Smuzhiyun static int i2s_trigger(struct snd_pcm_substream *substream,
930*4882a593Smuzhiyun int cmd, struct snd_soc_dai *dai)
931*4882a593Smuzhiyun {
932*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
933*4882a593Smuzhiyun int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
934*4882a593Smuzhiyun struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
935*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(asoc_rtd_to_cpu(rtd, 0));
936*4882a593Smuzhiyun unsigned long flags;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun switch (cmd) {
939*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_START:
940*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_RESUME:
941*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
942*4882a593Smuzhiyun pm_runtime_get_sync(dai->dev);
943*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
944*4882a593Smuzhiyun
945*4882a593Smuzhiyun if (config_setup(i2s)) {
946*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
947*4882a593Smuzhiyun return -EINVAL;
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun if (capture)
951*4882a593Smuzhiyun i2s_rxctrl(i2s, 1);
952*4882a593Smuzhiyun else
953*4882a593Smuzhiyun i2s_txctrl(i2s, 1);
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
956*4882a593Smuzhiyun break;
957*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_STOP:
958*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_SUSPEND:
959*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
960*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
961*4882a593Smuzhiyun
962*4882a593Smuzhiyun if (capture) {
963*4882a593Smuzhiyun i2s_rxctrl(i2s, 0);
964*4882a593Smuzhiyun i2s_fifo(i2s, FIC_RXFLUSH);
965*4882a593Smuzhiyun } else {
966*4882a593Smuzhiyun i2s_txctrl(i2s, 0);
967*4882a593Smuzhiyun i2s_fifo(i2s, FIC_TXFLUSH);
968*4882a593Smuzhiyun }
969*4882a593Smuzhiyun
970*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
971*4882a593Smuzhiyun pm_runtime_put(dai->dev);
972*4882a593Smuzhiyun break;
973*4882a593Smuzhiyun }
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun return 0;
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun
i2s_set_clkdiv(struct snd_soc_dai * dai,int div_id,int div)978*4882a593Smuzhiyun static int i2s_set_clkdiv(struct snd_soc_dai *dai,
979*4882a593Smuzhiyun int div_id, int div)
980*4882a593Smuzhiyun {
981*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(dai);
982*4882a593Smuzhiyun struct i2s_dai *other = get_other_dai(i2s);
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun switch (div_id) {
985*4882a593Smuzhiyun case SAMSUNG_I2S_DIV_BCLK:
986*4882a593Smuzhiyun pm_runtime_get_sync(dai->dev);
987*4882a593Smuzhiyun if ((any_active(i2s) && div && (get_bfs(i2s) != div))
988*4882a593Smuzhiyun || (other && other->bfs && (other->bfs != div))) {
989*4882a593Smuzhiyun pm_runtime_put(dai->dev);
990*4882a593Smuzhiyun dev_err(&i2s->pdev->dev,
991*4882a593Smuzhiyun "%s:%d Other DAI busy\n", __func__, __LINE__);
992*4882a593Smuzhiyun return -EAGAIN;
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun i2s->bfs = div;
995*4882a593Smuzhiyun pm_runtime_put(dai->dev);
996*4882a593Smuzhiyun break;
997*4882a593Smuzhiyun default:
998*4882a593Smuzhiyun dev_err(&i2s->pdev->dev,
999*4882a593Smuzhiyun "Invalid clock divider(%d)\n", div_id);
1000*4882a593Smuzhiyun return -EINVAL;
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun
1003*4882a593Smuzhiyun return 0;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun
1006*4882a593Smuzhiyun static snd_pcm_sframes_t
i2s_delay(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)1007*4882a593Smuzhiyun i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
1010*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(dai);
1011*4882a593Smuzhiyun u32 reg = readl(priv->addr + I2SFIC);
1012*4882a593Smuzhiyun snd_pcm_sframes_t delay;
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun WARN_ON(!pm_runtime_active(dai->dev));
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
1017*4882a593Smuzhiyun delay = FIC_RXCOUNT(reg);
1018*4882a593Smuzhiyun else if (is_secondary(i2s))
1019*4882a593Smuzhiyun delay = FICS_TXCOUNT(readl(priv->addr + I2SFICS));
1020*4882a593Smuzhiyun else
1021*4882a593Smuzhiyun delay = (reg >> priv->variant_regs->ftx0cnt_off) & 0x7f;
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun return delay;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun #ifdef CONFIG_PM
i2s_suspend(struct snd_soc_component * component)1027*4882a593Smuzhiyun static int i2s_suspend(struct snd_soc_component *component)
1028*4882a593Smuzhiyun {
1029*4882a593Smuzhiyun return pm_runtime_force_suspend(component->dev);
1030*4882a593Smuzhiyun }
1031*4882a593Smuzhiyun
i2s_resume(struct snd_soc_component * component)1032*4882a593Smuzhiyun static int i2s_resume(struct snd_soc_component *component)
1033*4882a593Smuzhiyun {
1034*4882a593Smuzhiyun return pm_runtime_force_resume(component->dev);
1035*4882a593Smuzhiyun }
1036*4882a593Smuzhiyun #else
1037*4882a593Smuzhiyun #define i2s_suspend NULL
1038*4882a593Smuzhiyun #define i2s_resume NULL
1039*4882a593Smuzhiyun #endif
1040*4882a593Smuzhiyun
samsung_i2s_dai_probe(struct snd_soc_dai * dai)1041*4882a593Smuzhiyun static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
1042*4882a593Smuzhiyun {
1043*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
1044*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(dai);
1045*4882a593Smuzhiyun struct i2s_dai *other = get_other_dai(i2s);
1046*4882a593Smuzhiyun unsigned long flags;
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun pm_runtime_get_sync(dai->dev);
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun if (is_secondary(i2s)) {
1051*4882a593Smuzhiyun /* If this is probe on the secondary DAI */
1052*4882a593Smuzhiyun snd_soc_dai_init_dma_data(dai, &i2s->dma_playback, NULL);
1053*4882a593Smuzhiyun } else {
1054*4882a593Smuzhiyun snd_soc_dai_init_dma_data(dai, &i2s->dma_playback,
1055*4882a593Smuzhiyun &i2s->dma_capture);
1056*4882a593Smuzhiyun
1057*4882a593Smuzhiyun if (priv->quirks & QUIRK_NEED_RSTCLR)
1058*4882a593Smuzhiyun writel(CON_RSTCLR, priv->addr + I2SCON);
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun if (priv->quirks & QUIRK_SUPPORTS_IDMA)
1061*4882a593Smuzhiyun idma_reg_addr_init(priv->addr,
1062*4882a593Smuzhiyun other->idma_playback.addr);
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun /* Reset any constraint on RFS and BFS */
1066*4882a593Smuzhiyun i2s->rfs = 0;
1067*4882a593Smuzhiyun i2s->bfs = 0;
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
1070*4882a593Smuzhiyun i2s_txctrl(i2s, 0);
1071*4882a593Smuzhiyun i2s_rxctrl(i2s, 0);
1072*4882a593Smuzhiyun i2s_fifo(i2s, FIC_TXFLUSH);
1073*4882a593Smuzhiyun i2s_fifo(other, FIC_TXFLUSH);
1074*4882a593Smuzhiyun i2s_fifo(i2s, FIC_RXFLUSH);
1075*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun /* Gate CDCLK by default */
1078*4882a593Smuzhiyun if (!is_opened(other))
1079*4882a593Smuzhiyun i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
1080*4882a593Smuzhiyun 0, SND_SOC_CLOCK_IN);
1081*4882a593Smuzhiyun pm_runtime_put(dai->dev);
1082*4882a593Smuzhiyun
1083*4882a593Smuzhiyun return 0;
1084*4882a593Smuzhiyun }
1085*4882a593Smuzhiyun
samsung_i2s_dai_remove(struct snd_soc_dai * dai)1086*4882a593Smuzhiyun static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
1087*4882a593Smuzhiyun {
1088*4882a593Smuzhiyun struct samsung_i2s_priv *priv = snd_soc_dai_get_drvdata(dai);
1089*4882a593Smuzhiyun struct i2s_dai *i2s = to_info(dai);
1090*4882a593Smuzhiyun unsigned long flags;
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun pm_runtime_get_sync(dai->dev);
1093*4882a593Smuzhiyun
1094*4882a593Smuzhiyun if (!is_secondary(i2s)) {
1095*4882a593Smuzhiyun if (priv->quirks & QUIRK_NEED_RSTCLR) {
1096*4882a593Smuzhiyun spin_lock_irqsave(&priv->lock, flags);
1097*4882a593Smuzhiyun writel(0, priv->addr + I2SCON);
1098*4882a593Smuzhiyun spin_unlock_irqrestore(&priv->lock, flags);
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun }
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun pm_runtime_put(dai->dev);
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun return 0;
1105*4882a593Smuzhiyun }
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
1108*4882a593Smuzhiyun .trigger = i2s_trigger,
1109*4882a593Smuzhiyun .hw_params = i2s_hw_params,
1110*4882a593Smuzhiyun .set_fmt = i2s_set_fmt,
1111*4882a593Smuzhiyun .set_clkdiv = i2s_set_clkdiv,
1112*4882a593Smuzhiyun .set_sysclk = i2s_set_sysclk,
1113*4882a593Smuzhiyun .startup = i2s_startup,
1114*4882a593Smuzhiyun .shutdown = i2s_shutdown,
1115*4882a593Smuzhiyun .delay = i2s_delay,
1116*4882a593Smuzhiyun };
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun static const struct snd_soc_dapm_widget samsung_i2s_widgets[] = {
1119*4882a593Smuzhiyun /* Backend DAI */
1120*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("Mixer DAI TX", NULL, 0, SND_SOC_NOPM, 0, 0),
1121*4882a593Smuzhiyun SND_SOC_DAPM_AIF_IN("Mixer DAI RX", NULL, 0, SND_SOC_NOPM, 0, 0),
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun /* Playback Mixer */
1124*4882a593Smuzhiyun SND_SOC_DAPM_MIXER("Playback Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
1125*4882a593Smuzhiyun };
1126*4882a593Smuzhiyun
1127*4882a593Smuzhiyun static const struct snd_soc_dapm_route samsung_i2s_dapm_routes[] = {
1128*4882a593Smuzhiyun { "Playback Mixer", NULL, "Primary Playback" },
1129*4882a593Smuzhiyun { "Playback Mixer", NULL, "Secondary Playback" },
1130*4882a593Smuzhiyun
1131*4882a593Smuzhiyun { "Mixer DAI TX", NULL, "Playback Mixer" },
1132*4882a593Smuzhiyun { "Primary Capture", NULL, "Mixer DAI RX" },
1133*4882a593Smuzhiyun };
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun static const struct snd_soc_component_driver samsung_i2s_component = {
1136*4882a593Smuzhiyun .name = "samsung-i2s",
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun .dapm_widgets = samsung_i2s_widgets,
1139*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(samsung_i2s_widgets),
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun .dapm_routes = samsung_i2s_dapm_routes,
1142*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(samsung_i2s_dapm_routes),
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun .suspend = i2s_suspend,
1145*4882a593Smuzhiyun .resume = i2s_resume,
1146*4882a593Smuzhiyun };
1147*4882a593Smuzhiyun
1148*4882a593Smuzhiyun #define SAMSUNG_I2S_FMTS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \
1149*4882a593Smuzhiyun SNDRV_PCM_FMTBIT_S24_LE)
1150*4882a593Smuzhiyun
i2s_alloc_dais(struct samsung_i2s_priv * priv,const struct samsung_i2s_dai_data * i2s_dai_data,int num_dais)1151*4882a593Smuzhiyun static int i2s_alloc_dais(struct samsung_i2s_priv *priv,
1152*4882a593Smuzhiyun const struct samsung_i2s_dai_data *i2s_dai_data,
1153*4882a593Smuzhiyun int num_dais)
1154*4882a593Smuzhiyun {
1155*4882a593Smuzhiyun static const char *dai_names[] = { "samsung-i2s", "samsung-i2s-sec" };
1156*4882a593Smuzhiyun static const char *stream_names[] = { "Primary Playback",
1157*4882a593Smuzhiyun "Secondary Playback" };
1158*4882a593Smuzhiyun struct snd_soc_dai_driver *dai_drv;
1159*4882a593Smuzhiyun struct i2s_dai *dai;
1160*4882a593Smuzhiyun int i;
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun priv->dai = devm_kcalloc(&priv->pdev->dev, num_dais,
1163*4882a593Smuzhiyun sizeof(*dai), GFP_KERNEL);
1164*4882a593Smuzhiyun if (!priv->dai)
1165*4882a593Smuzhiyun return -ENOMEM;
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun priv->dai_drv = devm_kcalloc(&priv->pdev->dev, num_dais,
1168*4882a593Smuzhiyun sizeof(*dai_drv), GFP_KERNEL);
1169*4882a593Smuzhiyun if (!priv->dai_drv)
1170*4882a593Smuzhiyun return -ENOMEM;
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun for (i = 0; i < num_dais; i++) {
1173*4882a593Smuzhiyun dai_drv = &priv->dai_drv[i];
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun dai_drv->probe = samsung_i2s_dai_probe;
1176*4882a593Smuzhiyun dai_drv->remove = samsung_i2s_dai_remove;
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun dai_drv->symmetric_rates = 1;
1179*4882a593Smuzhiyun dai_drv->ops = &samsung_i2s_dai_ops;
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun dai_drv->playback.channels_min = 1;
1182*4882a593Smuzhiyun dai_drv->playback.channels_max = 2;
1183*4882a593Smuzhiyun dai_drv->playback.rates = i2s_dai_data->pcm_rates;
1184*4882a593Smuzhiyun dai_drv->playback.formats = SAMSUNG_I2S_FMTS;
1185*4882a593Smuzhiyun dai_drv->playback.stream_name = stream_names[i];
1186*4882a593Smuzhiyun
1187*4882a593Smuzhiyun dai_drv->id = i + 1;
1188*4882a593Smuzhiyun dai_drv->name = dai_names[i];
1189*4882a593Smuzhiyun
1190*4882a593Smuzhiyun priv->dai[i].drv = &priv->dai_drv[i];
1191*4882a593Smuzhiyun priv->dai[i].pdev = priv->pdev;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun /* Initialize capture only for the primary DAI */
1195*4882a593Smuzhiyun dai_drv = &priv->dai_drv[SAMSUNG_I2S_ID_PRIMARY - 1];
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun dai_drv->capture.channels_min = 1;
1198*4882a593Smuzhiyun dai_drv->capture.channels_max = 2;
1199*4882a593Smuzhiyun dai_drv->capture.rates = i2s_dai_data->pcm_rates;
1200*4882a593Smuzhiyun dai_drv->capture.formats = SAMSUNG_I2S_FMTS;
1201*4882a593Smuzhiyun dai_drv->capture.stream_name = "Primary Capture";
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun return 0;
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun #ifdef CONFIG_PM
i2s_runtime_suspend(struct device * dev)1207*4882a593Smuzhiyun static int i2s_runtime_suspend(struct device *dev)
1208*4882a593Smuzhiyun {
1209*4882a593Smuzhiyun struct samsung_i2s_priv *priv = dev_get_drvdata(dev);
1210*4882a593Smuzhiyun
1211*4882a593Smuzhiyun priv->suspend_i2smod = readl(priv->addr + I2SMOD);
1212*4882a593Smuzhiyun priv->suspend_i2scon = readl(priv->addr + I2SCON);
1213*4882a593Smuzhiyun priv->suspend_i2spsr = readl(priv->addr + I2SPSR);
1214*4882a593Smuzhiyun
1215*4882a593Smuzhiyun if (priv->op_clk)
1216*4882a593Smuzhiyun clk_disable_unprepare(priv->op_clk);
1217*4882a593Smuzhiyun clk_disable_unprepare(priv->clk);
1218*4882a593Smuzhiyun
1219*4882a593Smuzhiyun return 0;
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun
i2s_runtime_resume(struct device * dev)1222*4882a593Smuzhiyun static int i2s_runtime_resume(struct device *dev)
1223*4882a593Smuzhiyun {
1224*4882a593Smuzhiyun struct samsung_i2s_priv *priv = dev_get_drvdata(dev);
1225*4882a593Smuzhiyun int ret;
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun ret = clk_prepare_enable(priv->clk);
1228*4882a593Smuzhiyun if (ret)
1229*4882a593Smuzhiyun return ret;
1230*4882a593Smuzhiyun
1231*4882a593Smuzhiyun if (priv->op_clk) {
1232*4882a593Smuzhiyun ret = clk_prepare_enable(priv->op_clk);
1233*4882a593Smuzhiyun if (ret) {
1234*4882a593Smuzhiyun clk_disable_unprepare(priv->clk);
1235*4882a593Smuzhiyun return ret;
1236*4882a593Smuzhiyun }
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun writel(priv->suspend_i2scon, priv->addr + I2SCON);
1240*4882a593Smuzhiyun writel(priv->suspend_i2smod, priv->addr + I2SMOD);
1241*4882a593Smuzhiyun writel(priv->suspend_i2spsr, priv->addr + I2SPSR);
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun return 0;
1244*4882a593Smuzhiyun }
1245*4882a593Smuzhiyun #endif /* CONFIG_PM */
1246*4882a593Smuzhiyun
i2s_unregister_clocks(struct samsung_i2s_priv * priv)1247*4882a593Smuzhiyun static void i2s_unregister_clocks(struct samsung_i2s_priv *priv)
1248*4882a593Smuzhiyun {
1249*4882a593Smuzhiyun int i;
1250*4882a593Smuzhiyun
1251*4882a593Smuzhiyun for (i = 0; i < priv->clk_data.clk_num; i++) {
1252*4882a593Smuzhiyun if (!IS_ERR(priv->clk_table[i]))
1253*4882a593Smuzhiyun clk_unregister(priv->clk_table[i]);
1254*4882a593Smuzhiyun }
1255*4882a593Smuzhiyun }
1256*4882a593Smuzhiyun
i2s_unregister_clock_provider(struct samsung_i2s_priv * priv)1257*4882a593Smuzhiyun static void i2s_unregister_clock_provider(struct samsung_i2s_priv *priv)
1258*4882a593Smuzhiyun {
1259*4882a593Smuzhiyun of_clk_del_provider(priv->pdev->dev.of_node);
1260*4882a593Smuzhiyun i2s_unregister_clocks(priv);
1261*4882a593Smuzhiyun }
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun
i2s_register_clock_provider(struct samsung_i2s_priv * priv)1264*4882a593Smuzhiyun static int i2s_register_clock_provider(struct samsung_i2s_priv *priv)
1265*4882a593Smuzhiyun {
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun const char * const i2s_clk_desc[] = { "cdclk", "rclk_src", "prescaler" };
1268*4882a593Smuzhiyun const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" };
1269*4882a593Smuzhiyun const char *p_names[2] = { NULL };
1270*4882a593Smuzhiyun struct device *dev = &priv->pdev->dev;
1271*4882a593Smuzhiyun const struct samsung_i2s_variant_regs *reg_info = priv->variant_regs;
1272*4882a593Smuzhiyun const char *i2s_clk_name[ARRAY_SIZE(i2s_clk_desc)];
1273*4882a593Smuzhiyun struct clk *rclksrc;
1274*4882a593Smuzhiyun int ret, i;
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun /* Register the clock provider only if it's expected in the DTB */
1277*4882a593Smuzhiyun if (!of_find_property(dev->of_node, "#clock-cells", NULL))
1278*4882a593Smuzhiyun return 0;
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun /* Get the RCLKSRC mux clock parent clock names */
1281*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(p_names); i++) {
1282*4882a593Smuzhiyun rclksrc = clk_get(dev, clk_name[i]);
1283*4882a593Smuzhiyun if (IS_ERR(rclksrc))
1284*4882a593Smuzhiyun continue;
1285*4882a593Smuzhiyun p_names[i] = __clk_get_name(rclksrc);
1286*4882a593Smuzhiyun clk_put(rclksrc);
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(i2s_clk_desc); i++) {
1290*4882a593Smuzhiyun i2s_clk_name[i] = devm_kasprintf(dev, GFP_KERNEL, "%s_%s",
1291*4882a593Smuzhiyun dev_name(dev), i2s_clk_desc[i]);
1292*4882a593Smuzhiyun if (!i2s_clk_name[i])
1293*4882a593Smuzhiyun return -ENOMEM;
1294*4882a593Smuzhiyun }
1295*4882a593Smuzhiyun
1296*4882a593Smuzhiyun if (!(priv->quirks & QUIRK_NO_MUXPSR)) {
1297*4882a593Smuzhiyun /* Activate the prescaler */
1298*4882a593Smuzhiyun u32 val = readl(priv->addr + I2SPSR);
1299*4882a593Smuzhiyun writel(val | PSR_PSREN, priv->addr + I2SPSR);
1300*4882a593Smuzhiyun
1301*4882a593Smuzhiyun priv->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(dev,
1302*4882a593Smuzhiyun i2s_clk_name[CLK_I2S_RCLK_SRC], p_names,
1303*4882a593Smuzhiyun ARRAY_SIZE(p_names),
1304*4882a593Smuzhiyun CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
1305*4882a593Smuzhiyun priv->addr + I2SMOD, reg_info->rclksrc_off,
1306*4882a593Smuzhiyun 1, 0, &priv->lock);
1307*4882a593Smuzhiyun
1308*4882a593Smuzhiyun priv->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(dev,
1309*4882a593Smuzhiyun i2s_clk_name[CLK_I2S_RCLK_PSR],
1310*4882a593Smuzhiyun i2s_clk_name[CLK_I2S_RCLK_SRC],
1311*4882a593Smuzhiyun CLK_SET_RATE_PARENT,
1312*4882a593Smuzhiyun priv->addr + I2SPSR, 8, 6, 0, &priv->lock);
1313*4882a593Smuzhiyun
1314*4882a593Smuzhiyun p_names[0] = i2s_clk_name[CLK_I2S_RCLK_PSR];
1315*4882a593Smuzhiyun priv->clk_data.clk_num = 2;
1316*4882a593Smuzhiyun }
1317*4882a593Smuzhiyun
1318*4882a593Smuzhiyun priv->clk_table[CLK_I2S_CDCLK] = clk_register_gate(dev,
1319*4882a593Smuzhiyun i2s_clk_name[CLK_I2S_CDCLK], p_names[0],
1320*4882a593Smuzhiyun CLK_SET_RATE_PARENT,
1321*4882a593Smuzhiyun priv->addr + I2SMOD, reg_info->cdclkcon_off,
1322*4882a593Smuzhiyun CLK_GATE_SET_TO_DISABLE, &priv->lock);
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun priv->clk_data.clk_num += 1;
1325*4882a593Smuzhiyun priv->clk_data.clks = priv->clk_table;
1326*4882a593Smuzhiyun
1327*4882a593Smuzhiyun ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
1328*4882a593Smuzhiyun &priv->clk_data);
1329*4882a593Smuzhiyun if (ret < 0) {
1330*4882a593Smuzhiyun dev_err(dev, "failed to add clock provider: %d\n", ret);
1331*4882a593Smuzhiyun i2s_unregister_clocks(priv);
1332*4882a593Smuzhiyun }
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun return ret;
1335*4882a593Smuzhiyun }
1336*4882a593Smuzhiyun
1337*4882a593Smuzhiyun /* Create platform device for the secondary PCM */
i2s_create_secondary_device(struct samsung_i2s_priv * priv)1338*4882a593Smuzhiyun static int i2s_create_secondary_device(struct samsung_i2s_priv *priv)
1339*4882a593Smuzhiyun {
1340*4882a593Smuzhiyun struct platform_device *pdev_sec;
1341*4882a593Smuzhiyun const char *devname;
1342*4882a593Smuzhiyun int ret;
1343*4882a593Smuzhiyun
1344*4882a593Smuzhiyun devname = devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, "%s-sec",
1345*4882a593Smuzhiyun dev_name(&priv->pdev->dev));
1346*4882a593Smuzhiyun if (!devname)
1347*4882a593Smuzhiyun return -ENOMEM;
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun pdev_sec = platform_device_alloc(devname, -1);
1350*4882a593Smuzhiyun if (!pdev_sec)
1351*4882a593Smuzhiyun return -ENOMEM;
1352*4882a593Smuzhiyun
1353*4882a593Smuzhiyun pdev_sec->driver_override = kstrdup("samsung-i2s", GFP_KERNEL);
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun ret = platform_device_add(pdev_sec);
1356*4882a593Smuzhiyun if (ret < 0) {
1357*4882a593Smuzhiyun platform_device_put(pdev_sec);
1358*4882a593Smuzhiyun return ret;
1359*4882a593Smuzhiyun }
1360*4882a593Smuzhiyun
1361*4882a593Smuzhiyun ret = device_attach(&pdev_sec->dev);
1362*4882a593Smuzhiyun if (ret <= 0) {
1363*4882a593Smuzhiyun platform_device_unregister(priv->pdev_sec);
1364*4882a593Smuzhiyun dev_info(&pdev_sec->dev, "device_attach() failed\n");
1365*4882a593Smuzhiyun return ret;
1366*4882a593Smuzhiyun }
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun priv->pdev_sec = pdev_sec;
1369*4882a593Smuzhiyun
1370*4882a593Smuzhiyun return 0;
1371*4882a593Smuzhiyun }
1372*4882a593Smuzhiyun
i2s_delete_secondary_device(struct samsung_i2s_priv * priv)1373*4882a593Smuzhiyun static void i2s_delete_secondary_device(struct samsung_i2s_priv *priv)
1374*4882a593Smuzhiyun {
1375*4882a593Smuzhiyun platform_device_unregister(priv->pdev_sec);
1376*4882a593Smuzhiyun priv->pdev_sec = NULL;
1377*4882a593Smuzhiyun }
1378*4882a593Smuzhiyun
samsung_i2s_probe(struct platform_device * pdev)1379*4882a593Smuzhiyun static int samsung_i2s_probe(struct platform_device *pdev)
1380*4882a593Smuzhiyun {
1381*4882a593Smuzhiyun struct i2s_dai *pri_dai, *sec_dai = NULL;
1382*4882a593Smuzhiyun struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data;
1383*4882a593Smuzhiyun u32 regs_base, idma_addr = 0;
1384*4882a593Smuzhiyun struct device_node *np = pdev->dev.of_node;
1385*4882a593Smuzhiyun const struct samsung_i2s_dai_data *i2s_dai_data;
1386*4882a593Smuzhiyun const struct platform_device_id *id;
1387*4882a593Smuzhiyun struct samsung_i2s_priv *priv;
1388*4882a593Smuzhiyun struct resource *res;
1389*4882a593Smuzhiyun int num_dais, ret;
1390*4882a593Smuzhiyun
1391*4882a593Smuzhiyun if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
1392*4882a593Smuzhiyun i2s_dai_data = of_device_get_match_data(&pdev->dev);
1393*4882a593Smuzhiyun } else {
1394*4882a593Smuzhiyun id = platform_get_device_id(pdev);
1395*4882a593Smuzhiyun
1396*4882a593Smuzhiyun /* Nothing to do if it is the secondary device probe */
1397*4882a593Smuzhiyun if (!id)
1398*4882a593Smuzhiyun return 0;
1399*4882a593Smuzhiyun
1400*4882a593Smuzhiyun i2s_dai_data = (struct samsung_i2s_dai_data *)id->driver_data;
1401*4882a593Smuzhiyun }
1402*4882a593Smuzhiyun
1403*4882a593Smuzhiyun priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1404*4882a593Smuzhiyun if (!priv)
1405*4882a593Smuzhiyun return -ENOMEM;
1406*4882a593Smuzhiyun
1407*4882a593Smuzhiyun if (np) {
1408*4882a593Smuzhiyun priv->quirks = i2s_dai_data->quirks;
1409*4882a593Smuzhiyun } else {
1410*4882a593Smuzhiyun if (!i2s_pdata) {
1411*4882a593Smuzhiyun dev_err(&pdev->dev, "Missing platform data\n");
1412*4882a593Smuzhiyun return -EINVAL;
1413*4882a593Smuzhiyun }
1414*4882a593Smuzhiyun priv->quirks = i2s_pdata->type.quirks;
1415*4882a593Smuzhiyun }
1416*4882a593Smuzhiyun
1417*4882a593Smuzhiyun num_dais = (priv->quirks & QUIRK_SEC_DAI) ? 2 : 1;
1418*4882a593Smuzhiyun priv->pdev = pdev;
1419*4882a593Smuzhiyun priv->variant_regs = i2s_dai_data->i2s_variant_regs;
1420*4882a593Smuzhiyun
1421*4882a593Smuzhiyun ret = i2s_alloc_dais(priv, i2s_dai_data, num_dais);
1422*4882a593Smuzhiyun if (ret < 0)
1423*4882a593Smuzhiyun return ret;
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun pri_dai = &priv->dai[SAMSUNG_I2S_ID_PRIMARY - 1];
1426*4882a593Smuzhiyun
1427*4882a593Smuzhiyun spin_lock_init(&priv->lock);
1428*4882a593Smuzhiyun spin_lock_init(&priv->pcm_lock);
1429*4882a593Smuzhiyun
1430*4882a593Smuzhiyun if (!np) {
1431*4882a593Smuzhiyun pri_dai->dma_playback.filter_data = i2s_pdata->dma_playback;
1432*4882a593Smuzhiyun pri_dai->dma_capture.filter_data = i2s_pdata->dma_capture;
1433*4882a593Smuzhiyun pri_dai->filter = i2s_pdata->dma_filter;
1434*4882a593Smuzhiyun
1435*4882a593Smuzhiyun idma_addr = i2s_pdata->type.idma_addr;
1436*4882a593Smuzhiyun } else {
1437*4882a593Smuzhiyun if (of_property_read_u32(np, "samsung,idma-addr",
1438*4882a593Smuzhiyun &idma_addr)) {
1439*4882a593Smuzhiyun if (priv->quirks & QUIRK_SUPPORTS_IDMA) {
1440*4882a593Smuzhiyun dev_info(&pdev->dev, "idma address is not"\
1441*4882a593Smuzhiyun "specified");
1442*4882a593Smuzhiyun }
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun
1446*4882a593Smuzhiyun res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1447*4882a593Smuzhiyun priv->addr = devm_ioremap_resource(&pdev->dev, res);
1448*4882a593Smuzhiyun if (IS_ERR(priv->addr))
1449*4882a593Smuzhiyun return PTR_ERR(priv->addr);
1450*4882a593Smuzhiyun
1451*4882a593Smuzhiyun regs_base = res->start;
1452*4882a593Smuzhiyun
1453*4882a593Smuzhiyun priv->clk = devm_clk_get(&pdev->dev, "iis");
1454*4882a593Smuzhiyun if (IS_ERR(priv->clk)) {
1455*4882a593Smuzhiyun dev_err(&pdev->dev, "Failed to get iis clock\n");
1456*4882a593Smuzhiyun return PTR_ERR(priv->clk);
1457*4882a593Smuzhiyun }
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun ret = clk_prepare_enable(priv->clk);
1460*4882a593Smuzhiyun if (ret != 0) {
1461*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
1462*4882a593Smuzhiyun return ret;
1463*4882a593Smuzhiyun }
1464*4882a593Smuzhiyun pri_dai->dma_playback.addr = regs_base + I2STXD;
1465*4882a593Smuzhiyun pri_dai->dma_capture.addr = regs_base + I2SRXD;
1466*4882a593Smuzhiyun pri_dai->dma_playback.chan_name = "tx";
1467*4882a593Smuzhiyun pri_dai->dma_capture.chan_name = "rx";
1468*4882a593Smuzhiyun pri_dai->dma_playback.addr_width = 4;
1469*4882a593Smuzhiyun pri_dai->dma_capture.addr_width = 4;
1470*4882a593Smuzhiyun pri_dai->priv = priv;
1471*4882a593Smuzhiyun
1472*4882a593Smuzhiyun if (priv->quirks & QUIRK_PRI_6CHAN)
1473*4882a593Smuzhiyun pri_dai->drv->playback.channels_max = 6;
1474*4882a593Smuzhiyun
1475*4882a593Smuzhiyun ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter,
1476*4882a593Smuzhiyun "tx", "rx", NULL);
1477*4882a593Smuzhiyun if (ret < 0)
1478*4882a593Smuzhiyun goto err_disable_clk;
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun if (priv->quirks & QUIRK_SEC_DAI) {
1481*4882a593Smuzhiyun sec_dai = &priv->dai[SAMSUNG_I2S_ID_SECONDARY - 1];
1482*4882a593Smuzhiyun
1483*4882a593Smuzhiyun sec_dai->dma_playback.addr = regs_base + I2STXDS;
1484*4882a593Smuzhiyun sec_dai->dma_playback.chan_name = "tx-sec";
1485*4882a593Smuzhiyun
1486*4882a593Smuzhiyun if (!np) {
1487*4882a593Smuzhiyun sec_dai->dma_playback.filter_data = i2s_pdata->dma_play_sec;
1488*4882a593Smuzhiyun sec_dai->filter = i2s_pdata->dma_filter;
1489*4882a593Smuzhiyun }
1490*4882a593Smuzhiyun
1491*4882a593Smuzhiyun sec_dai->dma_playback.addr_width = 4;
1492*4882a593Smuzhiyun sec_dai->idma_playback.addr = idma_addr;
1493*4882a593Smuzhiyun sec_dai->pri_dai = pri_dai;
1494*4882a593Smuzhiyun sec_dai->priv = priv;
1495*4882a593Smuzhiyun pri_dai->sec_dai = sec_dai;
1496*4882a593Smuzhiyun
1497*4882a593Smuzhiyun ret = i2s_create_secondary_device(priv);
1498*4882a593Smuzhiyun if (ret < 0)
1499*4882a593Smuzhiyun goto err_disable_clk;
1500*4882a593Smuzhiyun
1501*4882a593Smuzhiyun ret = samsung_asoc_dma_platform_register(&priv->pdev_sec->dev,
1502*4882a593Smuzhiyun sec_dai->filter, "tx-sec", NULL,
1503*4882a593Smuzhiyun &pdev->dev);
1504*4882a593Smuzhiyun if (ret < 0)
1505*4882a593Smuzhiyun goto err_del_sec;
1506*4882a593Smuzhiyun
1507*4882a593Smuzhiyun }
1508*4882a593Smuzhiyun
1509*4882a593Smuzhiyun if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
1510*4882a593Smuzhiyun dev_err(&pdev->dev, "Unable to configure gpio\n");
1511*4882a593Smuzhiyun ret = -EINVAL;
1512*4882a593Smuzhiyun goto err_del_sec;
1513*4882a593Smuzhiyun }
1514*4882a593Smuzhiyun
1515*4882a593Smuzhiyun dev_set_drvdata(&pdev->dev, priv);
1516*4882a593Smuzhiyun
1517*4882a593Smuzhiyun ret = devm_snd_soc_register_component(&pdev->dev,
1518*4882a593Smuzhiyun &samsung_i2s_component,
1519*4882a593Smuzhiyun priv->dai_drv, num_dais);
1520*4882a593Smuzhiyun if (ret < 0)
1521*4882a593Smuzhiyun goto err_del_sec;
1522*4882a593Smuzhiyun
1523*4882a593Smuzhiyun pm_runtime_set_active(&pdev->dev);
1524*4882a593Smuzhiyun pm_runtime_enable(&pdev->dev);
1525*4882a593Smuzhiyun
1526*4882a593Smuzhiyun ret = i2s_register_clock_provider(priv);
1527*4882a593Smuzhiyun if (ret < 0)
1528*4882a593Smuzhiyun goto err_disable_pm;
1529*4882a593Smuzhiyun
1530*4882a593Smuzhiyun priv->op_clk = clk_get_parent(priv->clk_table[CLK_I2S_RCLK_SRC]);
1531*4882a593Smuzhiyun
1532*4882a593Smuzhiyun return 0;
1533*4882a593Smuzhiyun
1534*4882a593Smuzhiyun err_disable_pm:
1535*4882a593Smuzhiyun pm_runtime_disable(&pdev->dev);
1536*4882a593Smuzhiyun err_del_sec:
1537*4882a593Smuzhiyun i2s_delete_secondary_device(priv);
1538*4882a593Smuzhiyun err_disable_clk:
1539*4882a593Smuzhiyun clk_disable_unprepare(priv->clk);
1540*4882a593Smuzhiyun return ret;
1541*4882a593Smuzhiyun }
1542*4882a593Smuzhiyun
samsung_i2s_remove(struct platform_device * pdev)1543*4882a593Smuzhiyun static int samsung_i2s_remove(struct platform_device *pdev)
1544*4882a593Smuzhiyun {
1545*4882a593Smuzhiyun struct samsung_i2s_priv *priv = dev_get_drvdata(&pdev->dev);
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun /* The secondary device has no driver data assigned */
1548*4882a593Smuzhiyun if (!priv)
1549*4882a593Smuzhiyun return 0;
1550*4882a593Smuzhiyun
1551*4882a593Smuzhiyun pm_runtime_get_sync(&pdev->dev);
1552*4882a593Smuzhiyun pm_runtime_disable(&pdev->dev);
1553*4882a593Smuzhiyun
1554*4882a593Smuzhiyun i2s_unregister_clock_provider(priv);
1555*4882a593Smuzhiyun i2s_delete_secondary_device(priv);
1556*4882a593Smuzhiyun clk_disable_unprepare(priv->clk);
1557*4882a593Smuzhiyun
1558*4882a593Smuzhiyun pm_runtime_put_noidle(&pdev->dev);
1559*4882a593Smuzhiyun
1560*4882a593Smuzhiyun return 0;
1561*4882a593Smuzhiyun }
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun static const struct samsung_i2s_variant_regs i2sv3_regs = {
1564*4882a593Smuzhiyun .bfs_off = 1,
1565*4882a593Smuzhiyun .rfs_off = 3,
1566*4882a593Smuzhiyun .sdf_off = 5,
1567*4882a593Smuzhiyun .txr_off = 8,
1568*4882a593Smuzhiyun .rclksrc_off = 10,
1569*4882a593Smuzhiyun .mss_off = 11,
1570*4882a593Smuzhiyun .cdclkcon_off = 12,
1571*4882a593Smuzhiyun .lrp_off = 7,
1572*4882a593Smuzhiyun .bfs_mask = 0x3,
1573*4882a593Smuzhiyun .rfs_mask = 0x3,
1574*4882a593Smuzhiyun .ftx0cnt_off = 8,
1575*4882a593Smuzhiyun };
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun static const struct samsung_i2s_variant_regs i2sv6_regs = {
1578*4882a593Smuzhiyun .bfs_off = 0,
1579*4882a593Smuzhiyun .rfs_off = 4,
1580*4882a593Smuzhiyun .sdf_off = 6,
1581*4882a593Smuzhiyun .txr_off = 8,
1582*4882a593Smuzhiyun .rclksrc_off = 10,
1583*4882a593Smuzhiyun .mss_off = 11,
1584*4882a593Smuzhiyun .cdclkcon_off = 12,
1585*4882a593Smuzhiyun .lrp_off = 15,
1586*4882a593Smuzhiyun .bfs_mask = 0xf,
1587*4882a593Smuzhiyun .rfs_mask = 0x3,
1588*4882a593Smuzhiyun .ftx0cnt_off = 8,
1589*4882a593Smuzhiyun };
1590*4882a593Smuzhiyun
1591*4882a593Smuzhiyun static const struct samsung_i2s_variant_regs i2sv7_regs = {
1592*4882a593Smuzhiyun .bfs_off = 0,
1593*4882a593Smuzhiyun .rfs_off = 4,
1594*4882a593Smuzhiyun .sdf_off = 7,
1595*4882a593Smuzhiyun .txr_off = 9,
1596*4882a593Smuzhiyun .rclksrc_off = 11,
1597*4882a593Smuzhiyun .mss_off = 12,
1598*4882a593Smuzhiyun .cdclkcon_off = 22,
1599*4882a593Smuzhiyun .lrp_off = 15,
1600*4882a593Smuzhiyun .bfs_mask = 0xf,
1601*4882a593Smuzhiyun .rfs_mask = 0x7,
1602*4882a593Smuzhiyun .ftx0cnt_off = 0,
1603*4882a593Smuzhiyun };
1604*4882a593Smuzhiyun
1605*4882a593Smuzhiyun static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = {
1606*4882a593Smuzhiyun .bfs_off = 0,
1607*4882a593Smuzhiyun .rfs_off = 3,
1608*4882a593Smuzhiyun .sdf_off = 6,
1609*4882a593Smuzhiyun .txr_off = 8,
1610*4882a593Smuzhiyun .rclksrc_off = 10,
1611*4882a593Smuzhiyun .mss_off = 11,
1612*4882a593Smuzhiyun .cdclkcon_off = 12,
1613*4882a593Smuzhiyun .lrp_off = 15,
1614*4882a593Smuzhiyun .bfs_mask = 0x7,
1615*4882a593Smuzhiyun .rfs_mask = 0x7,
1616*4882a593Smuzhiyun .ftx0cnt_off = 8,
1617*4882a593Smuzhiyun };
1618*4882a593Smuzhiyun
1619*4882a593Smuzhiyun static const struct samsung_i2s_dai_data i2sv3_dai_type = {
1620*4882a593Smuzhiyun .quirks = QUIRK_NO_MUXPSR,
1621*4882a593Smuzhiyun .pcm_rates = SNDRV_PCM_RATE_8000_96000,
1622*4882a593Smuzhiyun .i2s_variant_regs = &i2sv3_regs,
1623*4882a593Smuzhiyun };
1624*4882a593Smuzhiyun
1625*4882a593Smuzhiyun static const struct samsung_i2s_dai_data i2sv5_dai_type = {
1626*4882a593Smuzhiyun .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
1627*4882a593Smuzhiyun QUIRK_SUPPORTS_IDMA,
1628*4882a593Smuzhiyun .pcm_rates = SNDRV_PCM_RATE_8000_96000,
1629*4882a593Smuzhiyun .i2s_variant_regs = &i2sv3_regs,
1630*4882a593Smuzhiyun };
1631*4882a593Smuzhiyun
1632*4882a593Smuzhiyun static const struct samsung_i2s_dai_data i2sv6_dai_type = {
1633*4882a593Smuzhiyun .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
1634*4882a593Smuzhiyun QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA,
1635*4882a593Smuzhiyun .pcm_rates = SNDRV_PCM_RATE_8000_96000,
1636*4882a593Smuzhiyun .i2s_variant_regs = &i2sv6_regs,
1637*4882a593Smuzhiyun };
1638*4882a593Smuzhiyun
1639*4882a593Smuzhiyun static const struct samsung_i2s_dai_data i2sv7_dai_type = {
1640*4882a593Smuzhiyun .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
1641*4882a593Smuzhiyun QUIRK_SUPPORTS_TDM,
1642*4882a593Smuzhiyun .pcm_rates = SNDRV_PCM_RATE_8000_192000,
1643*4882a593Smuzhiyun .i2s_variant_regs = &i2sv7_regs,
1644*4882a593Smuzhiyun };
1645*4882a593Smuzhiyun
1646*4882a593Smuzhiyun static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = {
1647*4882a593Smuzhiyun .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR,
1648*4882a593Smuzhiyun .pcm_rates = SNDRV_PCM_RATE_8000_96000,
1649*4882a593Smuzhiyun .i2s_variant_regs = &i2sv5_i2s1_regs,
1650*4882a593Smuzhiyun };
1651*4882a593Smuzhiyun
1652*4882a593Smuzhiyun static const struct platform_device_id samsung_i2s_driver_ids[] = {
1653*4882a593Smuzhiyun {
1654*4882a593Smuzhiyun .name = "samsung-i2s",
1655*4882a593Smuzhiyun .driver_data = (kernel_ulong_t)&i2sv3_dai_type,
1656*4882a593Smuzhiyun },
1657*4882a593Smuzhiyun {},
1658*4882a593Smuzhiyun };
1659*4882a593Smuzhiyun MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
1660*4882a593Smuzhiyun
1661*4882a593Smuzhiyun #ifdef CONFIG_OF
1662*4882a593Smuzhiyun static const struct of_device_id exynos_i2s_match[] = {
1663*4882a593Smuzhiyun {
1664*4882a593Smuzhiyun .compatible = "samsung,s3c6410-i2s",
1665*4882a593Smuzhiyun .data = &i2sv3_dai_type,
1666*4882a593Smuzhiyun }, {
1667*4882a593Smuzhiyun .compatible = "samsung,s5pv210-i2s",
1668*4882a593Smuzhiyun .data = &i2sv5_dai_type,
1669*4882a593Smuzhiyun }, {
1670*4882a593Smuzhiyun .compatible = "samsung,exynos5420-i2s",
1671*4882a593Smuzhiyun .data = &i2sv6_dai_type,
1672*4882a593Smuzhiyun }, {
1673*4882a593Smuzhiyun .compatible = "samsung,exynos7-i2s",
1674*4882a593Smuzhiyun .data = &i2sv7_dai_type,
1675*4882a593Smuzhiyun }, {
1676*4882a593Smuzhiyun .compatible = "samsung,exynos7-i2s1",
1677*4882a593Smuzhiyun .data = &i2sv5_dai_type_i2s1,
1678*4882a593Smuzhiyun },
1679*4882a593Smuzhiyun {},
1680*4882a593Smuzhiyun };
1681*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, exynos_i2s_match);
1682*4882a593Smuzhiyun #endif
1683*4882a593Smuzhiyun
1684*4882a593Smuzhiyun static const struct dev_pm_ops samsung_i2s_pm = {
1685*4882a593Smuzhiyun SET_RUNTIME_PM_OPS(i2s_runtime_suspend,
1686*4882a593Smuzhiyun i2s_runtime_resume, NULL)
1687*4882a593Smuzhiyun SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
1688*4882a593Smuzhiyun pm_runtime_force_resume)
1689*4882a593Smuzhiyun };
1690*4882a593Smuzhiyun
1691*4882a593Smuzhiyun static struct platform_driver samsung_i2s_driver = {
1692*4882a593Smuzhiyun .probe = samsung_i2s_probe,
1693*4882a593Smuzhiyun .remove = samsung_i2s_remove,
1694*4882a593Smuzhiyun .id_table = samsung_i2s_driver_ids,
1695*4882a593Smuzhiyun .driver = {
1696*4882a593Smuzhiyun .name = "samsung-i2s",
1697*4882a593Smuzhiyun .of_match_table = of_match_ptr(exynos_i2s_match),
1698*4882a593Smuzhiyun .pm = &samsung_i2s_pm,
1699*4882a593Smuzhiyun },
1700*4882a593Smuzhiyun };
1701*4882a593Smuzhiyun
1702*4882a593Smuzhiyun module_platform_driver(samsung_i2s_driver);
1703*4882a593Smuzhiyun
1704*4882a593Smuzhiyun /* Module information */
1705*4882a593Smuzhiyun MODULE_AUTHOR("Jaswinder Singh, <jassisinghbrar@gmail.com>");
1706*4882a593Smuzhiyun MODULE_DESCRIPTION("Samsung I2S Interface");
1707*4882a593Smuzhiyun MODULE_ALIAS("platform:samsung-i2s");
1708*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1709