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