xref: /OK3568_Linux_fs/kernel/sound/soc/au1x/psc-ac97.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Au12x0/Au1550 PSC ALSA ASoC audio support.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * (c) 2007-2009 MSC Vertriebsges.m.b.H.,
6*4882a593Smuzhiyun  *	Manuel Lauss <manuel.lauss@gmail.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Au1xxx-PSC AC97 glue.
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/device.h>
15*4882a593Smuzhiyun #include <linux/delay.h>
16*4882a593Smuzhiyun #include <linux/mutex.h>
17*4882a593Smuzhiyun #include <linux/suspend.h>
18*4882a593Smuzhiyun #include <sound/core.h>
19*4882a593Smuzhiyun #include <sound/pcm.h>
20*4882a593Smuzhiyun #include <sound/initval.h>
21*4882a593Smuzhiyun #include <sound/soc.h>
22*4882a593Smuzhiyun #include <asm/mach-au1x00/au1000.h>
23*4882a593Smuzhiyun #include <asm/mach-au1x00/au1xxx_psc.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include "psc.h"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /* how often to retry failed codec register reads/writes */
28*4882a593Smuzhiyun #define AC97_RW_RETRIES	5
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define AC97_DIR	\
31*4882a593Smuzhiyun 	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define AC97_RATES	\
34*4882a593Smuzhiyun 	SNDRV_PCM_RATE_8000_48000
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #define AC97_FMTS	\
37*4882a593Smuzhiyun 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE)
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define AC97PCR_START(stype)	\
40*4882a593Smuzhiyun 	((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TS : PSC_AC97PCR_RS)
41*4882a593Smuzhiyun #define AC97PCR_STOP(stype)	\
42*4882a593Smuzhiyun 	((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TP : PSC_AC97PCR_RP)
43*4882a593Smuzhiyun #define AC97PCR_CLRFIFO(stype)	\
44*4882a593Smuzhiyun 	((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TC : PSC_AC97PCR_RC)
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define AC97STAT_BUSY(stype)	\
47*4882a593Smuzhiyun 	((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97STAT_TB : PSC_AC97STAT_RB)
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun /* instance data. There can be only one, MacLeod!!!! */
50*4882a593Smuzhiyun static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #if 0
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /* this could theoretically work, but ac97->bus->card->private_data can be NULL
55*4882a593Smuzhiyun  * when snd_ac97_mixer() is called; I don't know if the rest further down the
56*4882a593Smuzhiyun  * chain are always valid either.
57*4882a593Smuzhiyun  */
58*4882a593Smuzhiyun static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	struct snd_soc_card *c = x->bus->card->private_data;
61*4882a593Smuzhiyun 	return snd_soc_dai_get_drvdata(c->asoc_rtd_to_cpu(rtd, 0));
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #else
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define ac97_to_pscdata(x)	au1xpsc_ac97_workdata
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #endif
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /* AC97 controller reads codec register */
au1xpsc_ac97_read(struct snd_ac97 * ac97,unsigned short reg)71*4882a593Smuzhiyun static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
72*4882a593Smuzhiyun 					unsigned short reg)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
75*4882a593Smuzhiyun 	unsigned short retry, tmo;
76*4882a593Smuzhiyun 	unsigned long data;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	__raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
79*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	retry = AC97_RW_RETRIES;
82*4882a593Smuzhiyun 	do {
83*4882a593Smuzhiyun 		mutex_lock(&pscdata->lock);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 		__raw_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg),
86*4882a593Smuzhiyun 			  AC97_CDC(pscdata));
87*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 		tmo = 20;
90*4882a593Smuzhiyun 		do {
91*4882a593Smuzhiyun 			udelay(21);
92*4882a593Smuzhiyun 			if (__raw_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)
93*4882a593Smuzhiyun 				break;
94*4882a593Smuzhiyun 		} while (--tmo);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 		data = __raw_readl(AC97_CDC(pscdata));
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 		__raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
99*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 		mutex_unlock(&pscdata->lock);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 		if (reg != ((data >> 16) & 0x7f))
104*4882a593Smuzhiyun 			tmo = 1;	/* wrong register, try again */
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	} while (--retry && !tmo);
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	return retry ? data & 0xffff : 0xffff;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun /* AC97 controller writes to codec register */
au1xpsc_ac97_write(struct snd_ac97 * ac97,unsigned short reg,unsigned short val)112*4882a593Smuzhiyun static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
113*4882a593Smuzhiyun 				unsigned short val)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
116*4882a593Smuzhiyun 	unsigned int tmo, retry;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	__raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
119*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	retry = AC97_RW_RETRIES;
122*4882a593Smuzhiyun 	do {
123*4882a593Smuzhiyun 		mutex_lock(&pscdata->lock);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 		__raw_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff),
126*4882a593Smuzhiyun 			  AC97_CDC(pscdata));
127*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 		tmo = 20;
130*4882a593Smuzhiyun 		do {
131*4882a593Smuzhiyun 			udelay(21);
132*4882a593Smuzhiyun 			if (__raw_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)
133*4882a593Smuzhiyun 				break;
134*4882a593Smuzhiyun 		} while (--tmo);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 		__raw_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
137*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 		mutex_unlock(&pscdata->lock);
140*4882a593Smuzhiyun 	} while (--retry && !tmo);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun /* AC97 controller asserts a warm reset */
au1xpsc_ac97_warm_reset(struct snd_ac97 * ac97)144*4882a593Smuzhiyun static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	__raw_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
149*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
150*4882a593Smuzhiyun 	msleep(10);
151*4882a593Smuzhiyun 	__raw_writel(0, AC97_RST(pscdata));
152*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
au1xpsc_ac97_cold_reset(struct snd_ac97 * ac97)155*4882a593Smuzhiyun static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
158*4882a593Smuzhiyun 	int i;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* disable PSC during cold reset */
161*4882a593Smuzhiyun 	__raw_writel(0, AC97_CFG(au1xpsc_ac97_workdata));
162*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
163*4882a593Smuzhiyun 	__raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(pscdata));
164*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	/* issue cold reset */
167*4882a593Smuzhiyun 	__raw_writel(PSC_AC97RST_RST, AC97_RST(pscdata));
168*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
169*4882a593Smuzhiyun 	msleep(500);
170*4882a593Smuzhiyun 	__raw_writel(0, AC97_RST(pscdata));
171*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	/* enable PSC */
174*4882a593Smuzhiyun 	__raw_writel(PSC_CTRL_ENABLE, PSC_CTRL(pscdata));
175*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	/* wait for PSC to indicate it's ready */
178*4882a593Smuzhiyun 	i = 1000;
179*4882a593Smuzhiyun 	while (!((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i))
180*4882a593Smuzhiyun 		msleep(1);
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	if (i == 0) {
183*4882a593Smuzhiyun 		printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n");
184*4882a593Smuzhiyun 		return;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	/* enable the ac97 function */
188*4882a593Smuzhiyun 	__raw_writel(pscdata->cfg | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
189*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	/* wait for AC97 core to become ready */
192*4882a593Smuzhiyun 	i = 1000;
193*4882a593Smuzhiyun 	while (!((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i))
194*4882a593Smuzhiyun 		msleep(1);
195*4882a593Smuzhiyun 	if (i == 0)
196*4882a593Smuzhiyun 		printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n");
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun /* AC97 controller operations */
200*4882a593Smuzhiyun static struct snd_ac97_bus_ops psc_ac97_ops = {
201*4882a593Smuzhiyun 	.read		= au1xpsc_ac97_read,
202*4882a593Smuzhiyun 	.write		= au1xpsc_ac97_write,
203*4882a593Smuzhiyun 	.reset		= au1xpsc_ac97_cold_reset,
204*4882a593Smuzhiyun 	.warm_reset	= au1xpsc_ac97_warm_reset,
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun 
au1xpsc_ac97_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)207*4882a593Smuzhiyun static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
208*4882a593Smuzhiyun 				  struct snd_pcm_hw_params *params,
209*4882a593Smuzhiyun 				  struct snd_soc_dai *dai)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
212*4882a593Smuzhiyun 	unsigned long r, ro, stat;
213*4882a593Smuzhiyun 	int chans, t, stype = substream->stream;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	chans = params_channels(params);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	r = ro = __raw_readl(AC97_CFG(pscdata));
218*4882a593Smuzhiyun 	stat = __raw_readl(AC97_STAT(pscdata));
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	/* already active? */
221*4882a593Smuzhiyun 	if (stat & (PSC_AC97STAT_TB | PSC_AC97STAT_RB)) {
222*4882a593Smuzhiyun 		/* reject parameters not currently set up */
223*4882a593Smuzhiyun 		if ((PSC_AC97CFG_GET_LEN(r) != params->msbits) ||
224*4882a593Smuzhiyun 		    (pscdata->rate != params_rate(params)))
225*4882a593Smuzhiyun 			return -EINVAL;
226*4882a593Smuzhiyun 	} else {
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 		/* set sample bitdepth: REG[24:21]=(BITS-2)/2 */
229*4882a593Smuzhiyun 		r &= ~PSC_AC97CFG_LEN_MASK;
230*4882a593Smuzhiyun 		r |= PSC_AC97CFG_SET_LEN(params->msbits);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 		/* channels: enable slots for front L/R channel */
233*4882a593Smuzhiyun 		if (stype == SNDRV_PCM_STREAM_PLAYBACK) {
234*4882a593Smuzhiyun 			r &= ~PSC_AC97CFG_TXSLOT_MASK;
235*4882a593Smuzhiyun 			r |= PSC_AC97CFG_TXSLOT_ENA(3);
236*4882a593Smuzhiyun 			r |= PSC_AC97CFG_TXSLOT_ENA(4);
237*4882a593Smuzhiyun 		} else {
238*4882a593Smuzhiyun 			r &= ~PSC_AC97CFG_RXSLOT_MASK;
239*4882a593Smuzhiyun 			r |= PSC_AC97CFG_RXSLOT_ENA(3);
240*4882a593Smuzhiyun 			r |= PSC_AC97CFG_RXSLOT_ENA(4);
241*4882a593Smuzhiyun 		}
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 		/* do we need to poke the hardware? */
244*4882a593Smuzhiyun 		if (!(r ^ ro))
245*4882a593Smuzhiyun 			goto out;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 		/* ac97 engine is about to be disabled */
248*4882a593Smuzhiyun 		mutex_lock(&pscdata->lock);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 		/* disable AC97 device controller first... */
251*4882a593Smuzhiyun 		__raw_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
252*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 		/* ...wait for it... */
255*4882a593Smuzhiyun 		t = 100;
256*4882a593Smuzhiyun 		while ((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) && --t)
257*4882a593Smuzhiyun 			msleep(1);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 		if (!t)
260*4882a593Smuzhiyun 			printk(KERN_ERR "PSC-AC97: can't disable!\n");
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 		/* ...write config... */
263*4882a593Smuzhiyun 		__raw_writel(r, AC97_CFG(pscdata));
264*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 		/* ...enable the AC97 controller again... */
267*4882a593Smuzhiyun 		__raw_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
268*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 		/* ...and wait for ready bit */
271*4882a593Smuzhiyun 		t = 100;
272*4882a593Smuzhiyun 		while ((!(__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && --t)
273*4882a593Smuzhiyun 			msleep(1);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 		if (!t)
276*4882a593Smuzhiyun 			printk(KERN_ERR "PSC-AC97: can't enable!\n");
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		mutex_unlock(&pscdata->lock);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 		pscdata->cfg = r;
281*4882a593Smuzhiyun 		pscdata->rate = params_rate(params);
282*4882a593Smuzhiyun 	}
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun out:
285*4882a593Smuzhiyun 	return 0;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
au1xpsc_ac97_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)288*4882a593Smuzhiyun static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
289*4882a593Smuzhiyun 				int cmd, struct snd_soc_dai *dai)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
292*4882a593Smuzhiyun 	int ret, stype = substream->stream;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	ret = 0;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	switch (cmd) {
297*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_START:
298*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_RESUME:
299*4882a593Smuzhiyun 		__raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata));
300*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
301*4882a593Smuzhiyun 		__raw_writel(AC97PCR_START(stype), AC97_PCR(pscdata));
302*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
303*4882a593Smuzhiyun 		break;
304*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_STOP:
305*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_SUSPEND:
306*4882a593Smuzhiyun 		__raw_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata));
307*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 		while (__raw_readl(AC97_STAT(pscdata)) & AC97STAT_BUSY(stype))
310*4882a593Smuzhiyun 			asm volatile ("nop");
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 		__raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata));
313*4882a593Smuzhiyun 		wmb(); /* drain writebuffer */
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 		break;
316*4882a593Smuzhiyun 	default:
317*4882a593Smuzhiyun 		ret = -EINVAL;
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 	return ret;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
au1xpsc_ac97_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)322*4882a593Smuzhiyun static int au1xpsc_ac97_startup(struct snd_pcm_substream *substream,
323*4882a593Smuzhiyun 				struct snd_soc_dai *dai)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
326*4882a593Smuzhiyun 	snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]);
327*4882a593Smuzhiyun 	return 0;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun 
au1xpsc_ac97_probe(struct snd_soc_dai * dai)330*4882a593Smuzhiyun static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun 	return au1xpsc_ac97_workdata ? 0 : -ENODEV;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
336*4882a593Smuzhiyun 	.startup	= au1xpsc_ac97_startup,
337*4882a593Smuzhiyun 	.trigger	= au1xpsc_ac97_trigger,
338*4882a593Smuzhiyun 	.hw_params	= au1xpsc_ac97_hw_params,
339*4882a593Smuzhiyun };
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
342*4882a593Smuzhiyun 	.probe			= au1xpsc_ac97_probe,
343*4882a593Smuzhiyun 	.playback = {
344*4882a593Smuzhiyun 		.rates		= AC97_RATES,
345*4882a593Smuzhiyun 		.formats	= AC97_FMTS,
346*4882a593Smuzhiyun 		.channels_min	= 2,
347*4882a593Smuzhiyun 		.channels_max	= 2,
348*4882a593Smuzhiyun 	},
349*4882a593Smuzhiyun 	.capture = {
350*4882a593Smuzhiyun 		.rates		= AC97_RATES,
351*4882a593Smuzhiyun 		.formats	= AC97_FMTS,
352*4882a593Smuzhiyun 		.channels_min	= 2,
353*4882a593Smuzhiyun 		.channels_max	= 2,
354*4882a593Smuzhiyun 	},
355*4882a593Smuzhiyun 	.ops = &au1xpsc_ac97_dai_ops,
356*4882a593Smuzhiyun };
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun static const struct snd_soc_component_driver au1xpsc_ac97_component = {
359*4882a593Smuzhiyun 	.name		= "au1xpsc-ac97",
360*4882a593Smuzhiyun };
361*4882a593Smuzhiyun 
au1xpsc_ac97_drvprobe(struct platform_device * pdev)362*4882a593Smuzhiyun static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	int ret;
365*4882a593Smuzhiyun 	struct resource *dmares;
366*4882a593Smuzhiyun 	unsigned long sel;
367*4882a593Smuzhiyun 	struct au1xpsc_audio_data *wd;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	wd = devm_kzalloc(&pdev->dev, sizeof(struct au1xpsc_audio_data),
370*4882a593Smuzhiyun 			  GFP_KERNEL);
371*4882a593Smuzhiyun 	if (!wd)
372*4882a593Smuzhiyun 		return -ENOMEM;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	mutex_init(&wd->lock);
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	wd->mmio = devm_platform_ioremap_resource(pdev, 0);
377*4882a593Smuzhiyun 	if (IS_ERR(wd->mmio))
378*4882a593Smuzhiyun 		return PTR_ERR(wd->mmio);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
381*4882a593Smuzhiyun 	if (!dmares)
382*4882a593Smuzhiyun 		return -EBUSY;
383*4882a593Smuzhiyun 	wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
386*4882a593Smuzhiyun 	if (!dmares)
387*4882a593Smuzhiyun 		return -EBUSY;
388*4882a593Smuzhiyun 	wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	/* configuration: max dma trigger threshold, enable ac97 */
391*4882a593Smuzhiyun 	wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 |
392*4882a593Smuzhiyun 		  PSC_AC97CFG_DE_ENABLE;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	/* preserve PSC clock source set up by platform	 */
395*4882a593Smuzhiyun 	sel = __raw_readl(PSC_SEL(wd)) & PSC_SEL_CLK_MASK;
396*4882a593Smuzhiyun 	__raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
397*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
398*4882a593Smuzhiyun 	__raw_writel(0, PSC_SEL(wd));
399*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
400*4882a593Smuzhiyun 	__raw_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
401*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	/* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
404*4882a593Smuzhiyun 	memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
405*4882a593Smuzhiyun 	       sizeof(struct snd_soc_dai_driver));
406*4882a593Smuzhiyun 	wd->dai_drv.name = dev_name(&pdev->dev);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	platform_set_drvdata(pdev, wd);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	ret = snd_soc_set_ac97_ops(&psc_ac97_ops);
411*4882a593Smuzhiyun 	if (ret)
412*4882a593Smuzhiyun 		return ret;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component,
415*4882a593Smuzhiyun 					 &wd->dai_drv, 1);
416*4882a593Smuzhiyun 	if (ret)
417*4882a593Smuzhiyun 		return ret;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	au1xpsc_ac97_workdata = wd;
420*4882a593Smuzhiyun 	return 0;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
au1xpsc_ac97_drvremove(struct platform_device * pdev)423*4882a593Smuzhiyun static int au1xpsc_ac97_drvremove(struct platform_device *pdev)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	snd_soc_unregister_component(&pdev->dev);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	/* disable PSC completely */
430*4882a593Smuzhiyun 	__raw_writel(0, AC97_CFG(wd));
431*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
432*4882a593Smuzhiyun 	__raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
433*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	au1xpsc_ac97_workdata = NULL;	/* MDEV */
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	return 0;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun #ifdef CONFIG_PM
au1xpsc_ac97_drvsuspend(struct device * dev)441*4882a593Smuzhiyun static int au1xpsc_ac97_drvsuspend(struct device *dev)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	/* save interesting registers and disable PSC */
446*4882a593Smuzhiyun 	wd->pm[0] = __raw_readl(PSC_SEL(wd));
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	__raw_writel(0, AC97_CFG(wd));
449*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
450*4882a593Smuzhiyun 	__raw_writel(PSC_CTRL_DISABLE, PSC_CTRL(wd));
451*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	return 0;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun 
au1xpsc_ac97_drvresume(struct device * dev)456*4882a593Smuzhiyun static int au1xpsc_ac97_drvresume(struct device *dev)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun 	struct au1xpsc_audio_data *wd = dev_get_drvdata(dev);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	/* restore PSC clock config */
461*4882a593Smuzhiyun 	__raw_writel(wd->pm[0] | PSC_SEL_PS_AC97MODE, PSC_SEL(wd));
462*4882a593Smuzhiyun 	wmb(); /* drain writebuffer */
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	/* after this point the ac97 core will cold-reset the codec.
465*4882a593Smuzhiyun 	 * During cold-reset the PSC is reinitialized and the last
466*4882a593Smuzhiyun 	 * configuration set up in hw_params() is restored.
467*4882a593Smuzhiyun 	 */
468*4882a593Smuzhiyun 	return 0;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun static const struct dev_pm_ops au1xpscac97_pmops = {
472*4882a593Smuzhiyun 	.suspend	= au1xpsc_ac97_drvsuspend,
473*4882a593Smuzhiyun 	.resume		= au1xpsc_ac97_drvresume,
474*4882a593Smuzhiyun };
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun #define AU1XPSCAC97_PMOPS &au1xpscac97_pmops
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun #else
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun #define AU1XPSCAC97_PMOPS NULL
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun #endif
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun static struct platform_driver au1xpsc_ac97_driver = {
485*4882a593Smuzhiyun 	.driver	= {
486*4882a593Smuzhiyun 		.name	= "au1xpsc_ac97",
487*4882a593Smuzhiyun 		.pm	= AU1XPSCAC97_PMOPS,
488*4882a593Smuzhiyun 	},
489*4882a593Smuzhiyun 	.probe		= au1xpsc_ac97_drvprobe,
490*4882a593Smuzhiyun 	.remove		= au1xpsc_ac97_drvremove,
491*4882a593Smuzhiyun };
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun module_platform_driver(au1xpsc_ac97_driver);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun MODULE_LICENSE("GPL");
496*4882a593Smuzhiyun MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver");
497*4882a593Smuzhiyun MODULE_AUTHOR("Manuel Lauss");
498*4882a593Smuzhiyun 
499