xref: /openbmc/linux/sound/soc/au1x/ac97c.c (revision b3c70c9e)
1b3c70c9eSManuel Lauss /*
2b3c70c9eSManuel Lauss  * Au1000/Au1500/Au1100 AC97C controller driver for ASoC
3b3c70c9eSManuel Lauss  *
4b3c70c9eSManuel Lauss  * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
5b3c70c9eSManuel Lauss  *
6b3c70c9eSManuel Lauss  * based on the old ALSA driver originally written by
7b3c70c9eSManuel Lauss  *			Charles Eidsness <charles@cooper-street.com>
8b3c70c9eSManuel Lauss  */
9b3c70c9eSManuel Lauss 
10b3c70c9eSManuel Lauss #include <linux/init.h>
11b3c70c9eSManuel Lauss #include <linux/module.h>
12b3c70c9eSManuel Lauss #include <linux/slab.h>
13b3c70c9eSManuel Lauss #include <linux/device.h>
14b3c70c9eSManuel Lauss #include <linux/delay.h>
15b3c70c9eSManuel Lauss #include <linux/mutex.h>
16b3c70c9eSManuel Lauss #include <linux/platform_device.h>
17b3c70c9eSManuel Lauss #include <linux/suspend.h>
18b3c70c9eSManuel Lauss #include <sound/core.h>
19b3c70c9eSManuel Lauss #include <sound/pcm.h>
20b3c70c9eSManuel Lauss #include <sound/initval.h>
21b3c70c9eSManuel Lauss #include <sound/soc.h>
22b3c70c9eSManuel Lauss #include <asm/mach-au1x00/au1000.h>
23b3c70c9eSManuel Lauss 
24b3c70c9eSManuel Lauss #include "psc.h"
25b3c70c9eSManuel Lauss 
26b3c70c9eSManuel Lauss /* register offsets and bits */
27b3c70c9eSManuel Lauss #define AC97_CONFIG	0x00
28b3c70c9eSManuel Lauss #define AC97_STATUS	0x04
29b3c70c9eSManuel Lauss #define AC97_DATA	0x08
30b3c70c9eSManuel Lauss #define AC97_CMDRESP	0x0c
31b3c70c9eSManuel Lauss #define AC97_ENABLE	0x10
32b3c70c9eSManuel Lauss 
33b3c70c9eSManuel Lauss #define CFG_RC(x)	(((x) & 0x3ff) << 13)	/* valid rx slots mask */
34b3c70c9eSManuel Lauss #define CFG_XS(x)	(((x) & 0x3ff) << 3)	/* valid tx slots mask */
35b3c70c9eSManuel Lauss #define CFG_SG		(1 << 2)	/* sync gate */
36b3c70c9eSManuel Lauss #define CFG_SN		(1 << 1)	/* sync control */
37b3c70c9eSManuel Lauss #define CFG_RS		(1 << 0)	/* acrst# control */
38b3c70c9eSManuel Lauss #define STAT_XU		(1 << 11)	/* tx underflow */
39b3c70c9eSManuel Lauss #define STAT_XO		(1 << 10)	/* tx overflow */
40b3c70c9eSManuel Lauss #define STAT_RU		(1 << 9)	/* rx underflow */
41b3c70c9eSManuel Lauss #define STAT_RO		(1 << 8)	/* rx overflow */
42b3c70c9eSManuel Lauss #define STAT_RD		(1 << 7)	/* codec ready */
43b3c70c9eSManuel Lauss #define STAT_CP		(1 << 6)	/* command pending */
44b3c70c9eSManuel Lauss #define STAT_TE		(1 << 4)	/* tx fifo empty */
45b3c70c9eSManuel Lauss #define STAT_TF		(1 << 3)	/* tx fifo full */
46b3c70c9eSManuel Lauss #define STAT_RE		(1 << 1)	/* rx fifo empty */
47b3c70c9eSManuel Lauss #define STAT_RF		(1 << 0)	/* rx fifo full */
48b3c70c9eSManuel Lauss #define CMD_SET_DATA(x)	(((x) & 0xffff) << 16)
49b3c70c9eSManuel Lauss #define CMD_GET_DATA(x)	((x) & 0xffff)
50b3c70c9eSManuel Lauss #define CMD_READ	(1 << 7)
51b3c70c9eSManuel Lauss #define CMD_WRITE	(0 << 7)
52b3c70c9eSManuel Lauss #define CMD_IDX(x)	((x) & 0x7f)
53b3c70c9eSManuel Lauss #define EN_D		(1 << 1)	/* DISable bit */
54b3c70c9eSManuel Lauss #define EN_CE		(1 << 0)	/* clock enable bit */
55b3c70c9eSManuel Lauss 
56b3c70c9eSManuel Lauss /* how often to retry failed codec register reads/writes */
57b3c70c9eSManuel Lauss #define AC97_RW_RETRIES	5
58b3c70c9eSManuel Lauss 
59b3c70c9eSManuel Lauss #define AC97_RATES	\
60b3c70c9eSManuel Lauss 	SNDRV_PCM_RATE_CONTINUOUS
61b3c70c9eSManuel Lauss 
62b3c70c9eSManuel Lauss #define AC97_FMTS	\
63b3c70c9eSManuel Lauss 	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE)
64b3c70c9eSManuel Lauss 
65b3c70c9eSManuel Lauss /* instance data. There can be only one, MacLeod!!!!, fortunately there IS only
66b3c70c9eSManuel Lauss  * once AC97C on early Alchemy chips. The newer ones aren't so lucky.
67b3c70c9eSManuel Lauss  */
68b3c70c9eSManuel Lauss static struct au1xpsc_audio_data *ac97c_workdata;
69b3c70c9eSManuel Lauss #define ac97_to_ctx(x)		ac97c_workdata
70b3c70c9eSManuel Lauss 
71b3c70c9eSManuel Lauss static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg)
72b3c70c9eSManuel Lauss {
73b3c70c9eSManuel Lauss 	return __raw_readl(ctx->mmio + reg);
74b3c70c9eSManuel Lauss }
75b3c70c9eSManuel Lauss 
76b3c70c9eSManuel Lauss static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v)
77b3c70c9eSManuel Lauss {
78b3c70c9eSManuel Lauss 	__raw_writel(v, ctx->mmio + reg);
79b3c70c9eSManuel Lauss 	wmb();
80b3c70c9eSManuel Lauss }
81b3c70c9eSManuel Lauss 
82b3c70c9eSManuel Lauss static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97,
83b3c70c9eSManuel Lauss 					  unsigned short r)
84b3c70c9eSManuel Lauss {
85b3c70c9eSManuel Lauss 	struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
86b3c70c9eSManuel Lauss 	unsigned int tmo, retry;
87b3c70c9eSManuel Lauss 	unsigned long data;
88b3c70c9eSManuel Lauss 
89b3c70c9eSManuel Lauss 	data = ~0;
90b3c70c9eSManuel Lauss 	retry = AC97_RW_RETRIES;
91b3c70c9eSManuel Lauss 	do {
92b3c70c9eSManuel Lauss 		mutex_lock(&ctx->lock);
93b3c70c9eSManuel Lauss 
94b3c70c9eSManuel Lauss 		tmo = 5;
95b3c70c9eSManuel Lauss 		while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
96b3c70c9eSManuel Lauss 			udelay(21);	/* wait an ac97 frame time */
97b3c70c9eSManuel Lauss 		if (!tmo) {
98b3c70c9eSManuel Lauss 			pr_debug("ac97rd timeout #1\n");
99b3c70c9eSManuel Lauss 			goto next;
100b3c70c9eSManuel Lauss 		}
101b3c70c9eSManuel Lauss 
102b3c70c9eSManuel Lauss 		WR(ctx, AC97_CMDRESP, CMD_IDX(r) | CMD_READ);
103b3c70c9eSManuel Lauss 
104b3c70c9eSManuel Lauss 		/* stupid errata: data is only valid for 21us, so
105b3c70c9eSManuel Lauss 		 * poll, Forrest, poll...
106b3c70c9eSManuel Lauss 		 */
107b3c70c9eSManuel Lauss 		tmo = 0x10000;
108b3c70c9eSManuel Lauss 		while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
109b3c70c9eSManuel Lauss 			asm volatile ("nop");
110b3c70c9eSManuel Lauss 		data = RD(ctx, AC97_CMDRESP);
111b3c70c9eSManuel Lauss 
112b3c70c9eSManuel Lauss 		if (!tmo)
113b3c70c9eSManuel Lauss 			pr_debug("ac97rd timeout #2\n");
114b3c70c9eSManuel Lauss 
115b3c70c9eSManuel Lauss next:
116b3c70c9eSManuel Lauss 		mutex_unlock(&ctx->lock);
117b3c70c9eSManuel Lauss 	} while (--retry && !tmo);
118b3c70c9eSManuel Lauss 
119b3c70c9eSManuel Lauss 	pr_debug("AC97RD %04x %04lx %d\n", r, data, retry);
120b3c70c9eSManuel Lauss 
121b3c70c9eSManuel Lauss 	return retry ? data & 0xffff : 0xffff;
122b3c70c9eSManuel Lauss }
123b3c70c9eSManuel Lauss 
124b3c70c9eSManuel Lauss static void au1xac97c_ac97_write(struct snd_ac97 *ac97, unsigned short r,
125b3c70c9eSManuel Lauss 				 unsigned short v)
126b3c70c9eSManuel Lauss {
127b3c70c9eSManuel Lauss 	struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
128b3c70c9eSManuel Lauss 	unsigned int tmo, retry;
129b3c70c9eSManuel Lauss 
130b3c70c9eSManuel Lauss 	retry = AC97_RW_RETRIES;
131b3c70c9eSManuel Lauss 	do {
132b3c70c9eSManuel Lauss 		mutex_lock(&ctx->lock);
133b3c70c9eSManuel Lauss 
134b3c70c9eSManuel Lauss 		for (tmo = 5; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
135b3c70c9eSManuel Lauss 			udelay(21);
136b3c70c9eSManuel Lauss 		if (!tmo) {
137b3c70c9eSManuel Lauss 			pr_debug("ac97wr timeout #1\n");
138b3c70c9eSManuel Lauss 			goto next;
139b3c70c9eSManuel Lauss 		}
140b3c70c9eSManuel Lauss 
141b3c70c9eSManuel Lauss 		WR(ctx, AC97_CMDRESP, CMD_WRITE | CMD_IDX(r) | CMD_SET_DATA(v));
142b3c70c9eSManuel Lauss 
143b3c70c9eSManuel Lauss 		for (tmo = 10; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
144b3c70c9eSManuel Lauss 			udelay(21);
145b3c70c9eSManuel Lauss 		if (!tmo)
146b3c70c9eSManuel Lauss 			pr_debug("ac97wr timeout #2\n");
147b3c70c9eSManuel Lauss next:
148b3c70c9eSManuel Lauss 		mutex_unlock(&ctx->lock);
149b3c70c9eSManuel Lauss 	} while (--retry && !tmo);
150b3c70c9eSManuel Lauss 
151b3c70c9eSManuel Lauss 	pr_debug("AC97WR %04x %04x %d\n", r, v, retry);
152b3c70c9eSManuel Lauss }
153b3c70c9eSManuel Lauss 
154b3c70c9eSManuel Lauss static void au1xac97c_ac97_warm_reset(struct snd_ac97 *ac97)
155b3c70c9eSManuel Lauss {
156b3c70c9eSManuel Lauss 	struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
157b3c70c9eSManuel Lauss 
158b3c70c9eSManuel Lauss 	WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG | CFG_SN);
159b3c70c9eSManuel Lauss 	msleep(20);
160b3c70c9eSManuel Lauss 	WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG);
161b3c70c9eSManuel Lauss 	WR(ctx, AC97_CONFIG, ctx->cfg);
162b3c70c9eSManuel Lauss }
163b3c70c9eSManuel Lauss 
164b3c70c9eSManuel Lauss static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
165b3c70c9eSManuel Lauss {
166b3c70c9eSManuel Lauss 	struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
167b3c70c9eSManuel Lauss 	int i;
168b3c70c9eSManuel Lauss 
169b3c70c9eSManuel Lauss 	WR(ctx, AC97_CONFIG, ctx->cfg | CFG_RS);
170b3c70c9eSManuel Lauss 	msleep(500);
171b3c70c9eSManuel Lauss 	WR(ctx, AC97_CONFIG, ctx->cfg);
172b3c70c9eSManuel Lauss 
173b3c70c9eSManuel Lauss 	/* wait for codec ready */
174b3c70c9eSManuel Lauss 	i = 50;
175b3c70c9eSManuel Lauss 	while (((RD(ctx, AC97_STATUS) & STAT_RD) == 0) && --i)
176b3c70c9eSManuel Lauss 		msleep(20);
177b3c70c9eSManuel Lauss 	if (!i)
178b3c70c9eSManuel Lauss 		printk(KERN_ERR "ac97c: codec not ready after cold reset\n");
179b3c70c9eSManuel Lauss }
180b3c70c9eSManuel Lauss 
181b3c70c9eSManuel Lauss /* AC97 controller operations */
182b3c70c9eSManuel Lauss struct snd_ac97_bus_ops soc_ac97_ops = {
183b3c70c9eSManuel Lauss 	.read		= au1xac97c_ac97_read,
184b3c70c9eSManuel Lauss 	.write		= au1xac97c_ac97_write,
185b3c70c9eSManuel Lauss 	.reset		= au1xac97c_ac97_cold_reset,
186b3c70c9eSManuel Lauss 	.warm_reset	= au1xac97c_ac97_warm_reset,
187b3c70c9eSManuel Lauss };
188b3c70c9eSManuel Lauss EXPORT_SYMBOL_GPL(soc_ac97_ops);	/* globals be gone! */
189b3c70c9eSManuel Lauss 
190b3c70c9eSManuel Lauss static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
191b3c70c9eSManuel Lauss 				 struct snd_soc_dai *dai)
192b3c70c9eSManuel Lauss {
193b3c70c9eSManuel Lauss 	struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
194b3c70c9eSManuel Lauss 	snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]);
195b3c70c9eSManuel Lauss 	return 0;
196b3c70c9eSManuel Lauss }
197b3c70c9eSManuel Lauss 
198b3c70c9eSManuel Lauss static struct snd_soc_dai_ops alchemy_ac97c_ops = {
199b3c70c9eSManuel Lauss 	.startup		= alchemy_ac97c_startup,
200b3c70c9eSManuel Lauss };
201b3c70c9eSManuel Lauss 
202b3c70c9eSManuel Lauss static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
203b3c70c9eSManuel Lauss {
204b3c70c9eSManuel Lauss 	return ac97c_workdata ? 0 : -ENODEV;
205b3c70c9eSManuel Lauss }
206b3c70c9eSManuel Lauss 
207b3c70c9eSManuel Lauss static struct snd_soc_dai_driver au1xac97c_dai_driver = {
208b3c70c9eSManuel Lauss 	.name			= "alchemy-ac97c",
209b3c70c9eSManuel Lauss 	.ac97_control		= 1,
210b3c70c9eSManuel Lauss 	.probe			= au1xac97c_dai_probe,
211b3c70c9eSManuel Lauss 	.playback = {
212b3c70c9eSManuel Lauss 		.rates		= AC97_RATES,
213b3c70c9eSManuel Lauss 		.formats	= AC97_FMTS,
214b3c70c9eSManuel Lauss 		.channels_min	= 2,
215b3c70c9eSManuel Lauss 		.channels_max	= 2,
216b3c70c9eSManuel Lauss 	},
217b3c70c9eSManuel Lauss 	.capture = {
218b3c70c9eSManuel Lauss 		.rates		= AC97_RATES,
219b3c70c9eSManuel Lauss 		.formats	= AC97_FMTS,
220b3c70c9eSManuel Lauss 		.channels_min	= 2,
221b3c70c9eSManuel Lauss 		.channels_max	= 2,
222b3c70c9eSManuel Lauss 	},
223b3c70c9eSManuel Lauss 	.ops			= &alchemy_ac97c_ops,
224b3c70c9eSManuel Lauss };
225b3c70c9eSManuel Lauss 
226b3c70c9eSManuel Lauss static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
227b3c70c9eSManuel Lauss {
228b3c70c9eSManuel Lauss 	int ret;
229b3c70c9eSManuel Lauss 	struct resource *r;
230b3c70c9eSManuel Lauss 	struct au1xpsc_audio_data *ctx;
231b3c70c9eSManuel Lauss 
232b3c70c9eSManuel Lauss 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
233b3c70c9eSManuel Lauss 	if (!ctx)
234b3c70c9eSManuel Lauss 		return -ENOMEM;
235b3c70c9eSManuel Lauss 
236b3c70c9eSManuel Lauss 	mutex_init(&ctx->lock);
237b3c70c9eSManuel Lauss 
238b3c70c9eSManuel Lauss 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
239b3c70c9eSManuel Lauss 	if (!r) {
240b3c70c9eSManuel Lauss 		ret = -ENODEV;
241b3c70c9eSManuel Lauss 		goto out0;
242b3c70c9eSManuel Lauss 	}
243b3c70c9eSManuel Lauss 
244b3c70c9eSManuel Lauss 	ret = -EBUSY;
245b3c70c9eSManuel Lauss 	if (!request_mem_region(r->start, resource_size(r), pdev->name))
246b3c70c9eSManuel Lauss 		goto out0;
247b3c70c9eSManuel Lauss 
248b3c70c9eSManuel Lauss 	ctx->mmio = ioremap_nocache(r->start, resource_size(r));
249b3c70c9eSManuel Lauss 	if (!ctx->mmio)
250b3c70c9eSManuel Lauss 		goto out1;
251b3c70c9eSManuel Lauss 
252b3c70c9eSManuel Lauss 	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
253b3c70c9eSManuel Lauss 	if (!r)
254b3c70c9eSManuel Lauss 		goto out1;
255b3c70c9eSManuel Lauss 	ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start;
256b3c70c9eSManuel Lauss 
257b3c70c9eSManuel Lauss 	r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
258b3c70c9eSManuel Lauss 	if (!r)
259b3c70c9eSManuel Lauss 		goto out1;
260b3c70c9eSManuel Lauss 	ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start;
261b3c70c9eSManuel Lauss 
262b3c70c9eSManuel Lauss 	/* switch it on */
263b3c70c9eSManuel Lauss 	WR(ctx, AC97_ENABLE, EN_D | EN_CE);
264b3c70c9eSManuel Lauss 	WR(ctx, AC97_ENABLE, EN_CE);
265b3c70c9eSManuel Lauss 
266b3c70c9eSManuel Lauss 	ctx->cfg = CFG_RC(3) | CFG_XS(3);
267b3c70c9eSManuel Lauss 	WR(ctx, AC97_CONFIG, ctx->cfg);
268b3c70c9eSManuel Lauss 
269b3c70c9eSManuel Lauss 	platform_set_drvdata(pdev, ctx);
270b3c70c9eSManuel Lauss 
271b3c70c9eSManuel Lauss 	ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
272b3c70c9eSManuel Lauss 	if (ret)
273b3c70c9eSManuel Lauss 		goto out1;
274b3c70c9eSManuel Lauss 
275b3c70c9eSManuel Lauss 	ac97c_workdata = ctx;
276b3c70c9eSManuel Lauss 	return 0;
277b3c70c9eSManuel Lauss 
278b3c70c9eSManuel Lauss 
279b3c70c9eSManuel Lauss 	snd_soc_unregister_dai(&pdev->dev);
280b3c70c9eSManuel Lauss out1:
281b3c70c9eSManuel Lauss 	release_mem_region(r->start, resource_size(r));
282b3c70c9eSManuel Lauss out0:
283b3c70c9eSManuel Lauss 	kfree(ctx);
284b3c70c9eSManuel Lauss 	return ret;
285b3c70c9eSManuel Lauss }
286b3c70c9eSManuel Lauss 
287b3c70c9eSManuel Lauss static int __devexit au1xac97c_drvremove(struct platform_device *pdev)
288b3c70c9eSManuel Lauss {
289b3c70c9eSManuel Lauss 	struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
290b3c70c9eSManuel Lauss 	struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
291b3c70c9eSManuel Lauss 
292b3c70c9eSManuel Lauss 	snd_soc_unregister_dai(&pdev->dev);
293b3c70c9eSManuel Lauss 
294b3c70c9eSManuel Lauss 	WR(ctx, AC97_ENABLE, EN_D);	/* clock off, disable */
295b3c70c9eSManuel Lauss 
296b3c70c9eSManuel Lauss 	iounmap(ctx->mmio);
297b3c70c9eSManuel Lauss 	release_mem_region(r->start, resource_size(r));
298b3c70c9eSManuel Lauss 	kfree(ctx);
299b3c70c9eSManuel Lauss 
300b3c70c9eSManuel Lauss 	ac97c_workdata = NULL;	/* MDEV */
301b3c70c9eSManuel Lauss 
302b3c70c9eSManuel Lauss 	return 0;
303b3c70c9eSManuel Lauss }
304b3c70c9eSManuel Lauss 
305b3c70c9eSManuel Lauss #ifdef CONFIG_PM
306b3c70c9eSManuel Lauss static int au1xac97c_drvsuspend(struct device *dev)
307b3c70c9eSManuel Lauss {
308b3c70c9eSManuel Lauss 	struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
309b3c70c9eSManuel Lauss 
310b3c70c9eSManuel Lauss 	WR(ctx, AC97_ENABLE, EN_D);	/* clock off, disable */
311b3c70c9eSManuel Lauss 
312b3c70c9eSManuel Lauss 	return 0;
313b3c70c9eSManuel Lauss }
314b3c70c9eSManuel Lauss 
315b3c70c9eSManuel Lauss static int au1xac97c_drvresume(struct device *dev)
316b3c70c9eSManuel Lauss {
317b3c70c9eSManuel Lauss 	struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
318b3c70c9eSManuel Lauss 
319b3c70c9eSManuel Lauss 	WR(ctx, AC97_ENABLE, EN_D | EN_CE);
320b3c70c9eSManuel Lauss 	WR(ctx, AC97_ENABLE, EN_CE);
321b3c70c9eSManuel Lauss 	WR(ctx, AC97_CONFIG, ctx->cfg);
322b3c70c9eSManuel Lauss 
323b3c70c9eSManuel Lauss 	return 0;
324b3c70c9eSManuel Lauss }
325b3c70c9eSManuel Lauss 
326b3c70c9eSManuel Lauss static const struct dev_pm_ops au1xpscac97_pmops = {
327b3c70c9eSManuel Lauss 	.suspend	= au1xac97c_drvsuspend,
328b3c70c9eSManuel Lauss 	.resume		= au1xac97c_drvresume,
329b3c70c9eSManuel Lauss };
330b3c70c9eSManuel Lauss 
331b3c70c9eSManuel Lauss #define AU1XPSCAC97_PMOPS (&au1xpscac97_pmops)
332b3c70c9eSManuel Lauss 
333b3c70c9eSManuel Lauss #else
334b3c70c9eSManuel Lauss 
335b3c70c9eSManuel Lauss #define AU1XPSCAC97_PMOPS NULL
336b3c70c9eSManuel Lauss 
337b3c70c9eSManuel Lauss #endif
338b3c70c9eSManuel Lauss 
339b3c70c9eSManuel Lauss static struct platform_driver au1xac97c_driver = {
340b3c70c9eSManuel Lauss 	.driver	= {
341b3c70c9eSManuel Lauss 		.name	= "alchemy-ac97c",
342b3c70c9eSManuel Lauss 		.owner	= THIS_MODULE,
343b3c70c9eSManuel Lauss 		.pm	= AU1XPSCAC97_PMOPS,
344b3c70c9eSManuel Lauss 	},
345b3c70c9eSManuel Lauss 	.probe		= au1xac97c_drvprobe,
346b3c70c9eSManuel Lauss 	.remove		= __devexit_p(au1xac97c_drvremove),
347b3c70c9eSManuel Lauss };
348b3c70c9eSManuel Lauss 
349b3c70c9eSManuel Lauss static int __init au1xac97c_load(void)
350b3c70c9eSManuel Lauss {
351b3c70c9eSManuel Lauss 	ac97c_workdata = NULL;
352b3c70c9eSManuel Lauss 	return platform_driver_register(&au1xac97c_driver);
353b3c70c9eSManuel Lauss }
354b3c70c9eSManuel Lauss 
355b3c70c9eSManuel Lauss static void __exit au1xac97c_unload(void)
356b3c70c9eSManuel Lauss {
357b3c70c9eSManuel Lauss 	platform_driver_unregister(&au1xac97c_driver);
358b3c70c9eSManuel Lauss }
359b3c70c9eSManuel Lauss 
360b3c70c9eSManuel Lauss module_init(au1xac97c_load);
361b3c70c9eSManuel Lauss module_exit(au1xac97c_unload);
362b3c70c9eSManuel Lauss 
363b3c70c9eSManuel Lauss MODULE_LICENSE("GPL");
364b3c70c9eSManuel Lauss MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver");
365b3c70c9eSManuel Lauss MODULE_AUTHOR("Manuel Lauss");
366