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