1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Based on sound/arm/pxa2xx-ac97.c and sound/soc/pxa/pxa2xx-ac97.c |
4 | * which contain: |
5 | * |
6 | * Author: Nicolas Pitre |
7 | * Created: Dec 02, 2004 |
8 | * Copyright: MontaVista Software Inc. |
9 | */ |
10 | |
11 | #include <linux/kernel.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/clk.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/module.h> |
17 | #include <linux/io.h> |
18 | #include <linux/gpio.h> |
19 | #include <linux/of_gpio.h> |
20 | #include <linux/soc/pxa/cpu.h> |
21 | |
22 | #include <sound/pxa2xx-lib.h> |
23 | |
24 | #include <linux/platform_data/asoc-pxa.h> |
25 | |
26 | #include "pxa2xx-ac97-regs.h" |
27 | |
28 | static DEFINE_MUTEX(car_mutex); |
29 | static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); |
30 | static volatile long gsr_bits; |
31 | static struct clk *ac97_clk; |
32 | static struct clk *ac97conf_clk; |
33 | static int reset_gpio; |
34 | static void __iomem *ac97_reg_base; |
35 | |
36 | /* |
37 | * Beware PXA27x bugs: |
38 | * |
39 | * o Slot 12 read from modem space will hang controller. |
40 | * o CDONE, SDONE interrupt fails after any slot 12 IO. |
41 | * |
42 | * We therefore have an hybrid approach for waiting on SDONE (interrupt or |
43 | * 1 jiffy timeout if interrupt never comes). |
44 | */ |
45 | |
46 | int pxa2xx_ac97_read(int slot, unsigned short reg) |
47 | { |
48 | int val = -ENODEV; |
49 | u32 __iomem *reg_addr; |
50 | |
51 | if (slot > 0) |
52 | return -ENODEV; |
53 | |
54 | mutex_lock(&car_mutex); |
55 | |
56 | /* set up primary or secondary codec space */ |
57 | if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) |
58 | reg_addr = ac97_reg_base + |
59 | (slot ? SMC_REG_BASE : PMC_REG_BASE); |
60 | else |
61 | reg_addr = ac97_reg_base + |
62 | (slot ? SAC_REG_BASE : PAC_REG_BASE); |
63 | reg_addr += (reg >> 1); |
64 | |
65 | /* start read access across the ac97 link */ |
66 | writel(GSR_CDONE | GSR_SDONE, addr: ac97_reg_base + GSR); |
67 | gsr_bits = 0; |
68 | val = (readl(addr: reg_addr) & 0xffff); |
69 | if (reg == AC97_GPIO_STATUS) |
70 | goto out; |
71 | if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1) <= 0 && |
72 | !((readl(addr: ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE)) { |
73 | printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n" , |
74 | __func__, reg, readl(ac97_reg_base + GSR) | gsr_bits); |
75 | val = -ETIMEDOUT; |
76 | goto out; |
77 | } |
78 | |
79 | /* valid data now */ |
80 | writel(GSR_CDONE | GSR_SDONE, addr: ac97_reg_base + GSR); |
81 | gsr_bits = 0; |
82 | val = (readl(addr: reg_addr) & 0xffff); |
83 | /* but we've just started another cycle... */ |
84 | wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_SDONE, 1); |
85 | |
86 | out: mutex_unlock(lock: &car_mutex); |
87 | return val; |
88 | } |
89 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_read); |
90 | |
91 | int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val) |
92 | { |
93 | u32 __iomem *reg_addr; |
94 | int ret = 0; |
95 | |
96 | mutex_lock(&car_mutex); |
97 | |
98 | /* set up primary or secondary codec space */ |
99 | if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS) |
100 | reg_addr = ac97_reg_base + |
101 | (slot ? SMC_REG_BASE : PMC_REG_BASE); |
102 | else |
103 | reg_addr = ac97_reg_base + |
104 | (slot ? SAC_REG_BASE : PAC_REG_BASE); |
105 | reg_addr += (reg >> 1); |
106 | |
107 | writel(GSR_CDONE | GSR_SDONE, addr: ac97_reg_base + GSR); |
108 | gsr_bits = 0; |
109 | writel(val, addr: reg_addr); |
110 | if (wait_event_timeout(gsr_wq, (readl(ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE, 1) <= 0 && |
111 | !((readl(addr: ac97_reg_base + GSR) | gsr_bits) & GSR_CDONE)) { |
112 | printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n" , |
113 | __func__, reg, readl(ac97_reg_base + GSR) | gsr_bits); |
114 | ret = -EIO; |
115 | } |
116 | |
117 | mutex_unlock(lock: &car_mutex); |
118 | return ret; |
119 | } |
120 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_write); |
121 | |
122 | #ifdef CONFIG_PXA25x |
123 | static inline void pxa_ac97_warm_pxa25x(void) |
124 | { |
125 | gsr_bits = 0; |
126 | |
127 | writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR); |
128 | } |
129 | |
130 | static inline void pxa_ac97_cold_pxa25x(void) |
131 | { |
132 | writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR); /* clear everything but nCRST */ |
133 | writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR); /* then assert nCRST */ |
134 | |
135 | gsr_bits = 0; |
136 | |
137 | writel(GCR_COLD_RST, ac97_reg_base + GCR); |
138 | } |
139 | #endif |
140 | |
141 | #ifdef CONFIG_PXA27x |
142 | static inline void pxa_ac97_warm_pxa27x(void) |
143 | { |
144 | gsr_bits = 0; |
145 | |
146 | /* warm reset broken on Bulverde, so manually keep AC97 reset high */ |
147 | pxa27x_configure_ac97reset(reset_gpio, true); |
148 | udelay(10); |
149 | writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR); |
150 | pxa27x_configure_ac97reset(reset_gpio, false); |
151 | udelay(500); |
152 | } |
153 | |
154 | static inline void pxa_ac97_cold_pxa27x(void) |
155 | { |
156 | writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR); /* clear everything but nCRST */ |
157 | writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR); /* then assert nCRST */ |
158 | |
159 | gsr_bits = 0; |
160 | |
161 | /* PXA27x Developers Manual section 13.5.2.2.1 */ |
162 | clk_prepare_enable(ac97conf_clk); |
163 | udelay(5); |
164 | clk_disable_unprepare(ac97conf_clk); |
165 | writel(GCR_COLD_RST | GCR_WARM_RST, ac97_reg_base + GCR); |
166 | } |
167 | #endif |
168 | |
169 | #ifdef CONFIG_PXA3xx |
170 | static inline void pxa_ac97_warm_pxa3xx(void) |
171 | { |
172 | gsr_bits = 0; |
173 | |
174 | /* Can't use interrupts */ |
175 | writel(readl(ac97_reg_base + GCR) | (GCR_WARM_RST), ac97_reg_base + GCR); |
176 | } |
177 | |
178 | static inline void pxa_ac97_cold_pxa3xx(void) |
179 | { |
180 | /* Hold CLKBPB for 100us */ |
181 | writel(0, ac97_reg_base + GCR); |
182 | writel(GCR_CLKBPB, ac97_reg_base + GCR); |
183 | udelay(100); |
184 | writel(0, ac97_reg_base + GCR); |
185 | |
186 | writel(readl(ac97_reg_base + GCR) & ( GCR_COLD_RST), ac97_reg_base + GCR); /* clear everything but nCRST */ |
187 | writel(readl(ac97_reg_base + GCR) & (~GCR_COLD_RST), ac97_reg_base + GCR); /* then assert nCRST */ |
188 | |
189 | gsr_bits = 0; |
190 | |
191 | /* Can't use interrupts on PXA3xx */ |
192 | writel(readl(ac97_reg_base + GCR) & (~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN)), ac97_reg_base + GCR); |
193 | |
194 | writel(GCR_WARM_RST | GCR_COLD_RST, ac97_reg_base + GCR); |
195 | } |
196 | #endif |
197 | |
198 | bool pxa2xx_ac97_try_warm_reset(void) |
199 | { |
200 | unsigned long gsr; |
201 | unsigned int timeout = 100; |
202 | |
203 | #ifdef CONFIG_PXA25x |
204 | if (cpu_is_pxa25x()) |
205 | pxa_ac97_warm_pxa25x(); |
206 | else |
207 | #endif |
208 | #ifdef CONFIG_PXA27x |
209 | if (cpu_is_pxa27x()) |
210 | pxa_ac97_warm_pxa27x(); |
211 | else |
212 | #endif |
213 | #ifdef CONFIG_PXA3xx |
214 | if (cpu_is_pxa3xx()) |
215 | pxa_ac97_warm_pxa3xx(); |
216 | else |
217 | #endif |
218 | snd_BUG(); |
219 | |
220 | while (!((readl(addr: ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) |
221 | mdelay(1); |
222 | |
223 | gsr = readl(addr: ac97_reg_base + GSR) | gsr_bits; |
224 | if (!(gsr & (GSR_PCR | GSR_SCR))) { |
225 | printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n" , |
226 | __func__, gsr); |
227 | |
228 | return false; |
229 | } |
230 | |
231 | return true; |
232 | } |
233 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset); |
234 | |
235 | bool pxa2xx_ac97_try_cold_reset(void) |
236 | { |
237 | unsigned long gsr; |
238 | unsigned int timeout = 1000; |
239 | |
240 | #ifdef CONFIG_PXA25x |
241 | if (cpu_is_pxa25x()) |
242 | pxa_ac97_cold_pxa25x(); |
243 | else |
244 | #endif |
245 | #ifdef CONFIG_PXA27x |
246 | if (cpu_is_pxa27x()) |
247 | pxa_ac97_cold_pxa27x(); |
248 | else |
249 | #endif |
250 | #ifdef CONFIG_PXA3xx |
251 | if (cpu_is_pxa3xx()) |
252 | pxa_ac97_cold_pxa3xx(); |
253 | else |
254 | #endif |
255 | snd_BUG(); |
256 | |
257 | while (!((readl(addr: ac97_reg_base + GSR) | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) |
258 | mdelay(1); |
259 | |
260 | gsr = readl(addr: ac97_reg_base + GSR) | gsr_bits; |
261 | if (!(gsr & (GSR_PCR | GSR_SCR))) { |
262 | printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n" , |
263 | __func__, gsr); |
264 | |
265 | return false; |
266 | } |
267 | |
268 | return true; |
269 | } |
270 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset); |
271 | |
272 | |
273 | void pxa2xx_ac97_finish_reset(void) |
274 | { |
275 | u32 gcr = readl(addr: ac97_reg_base + GCR); |
276 | gcr &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); |
277 | gcr |= GCR_SDONE_IE|GCR_CDONE_IE; |
278 | writel(val: gcr, addr: ac97_reg_base + GCR); |
279 | } |
280 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset); |
281 | |
282 | static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) |
283 | { |
284 | long status; |
285 | |
286 | status = readl(addr: ac97_reg_base + GSR); |
287 | if (status) { |
288 | writel(val: status, addr: ac97_reg_base + GSR); |
289 | gsr_bits |= status; |
290 | wake_up(&gsr_wq); |
291 | |
292 | /* Although we don't use those we still need to clear them |
293 | since they tend to spuriously trigger when MMC is used |
294 | (hardware bug? go figure)... */ |
295 | if (cpu_is_pxa27x()) { |
296 | writel(MISR_EOC, addr: ac97_reg_base + MISR); |
297 | writel(PISR_EOC, addr: ac97_reg_base + PISR); |
298 | writel(MCSR_EOC, addr: ac97_reg_base + MCSR); |
299 | } |
300 | |
301 | return IRQ_HANDLED; |
302 | } |
303 | |
304 | return IRQ_NONE; |
305 | } |
306 | |
307 | #ifdef CONFIG_PM |
308 | int pxa2xx_ac97_hw_suspend(void) |
309 | { |
310 | writel(readl(addr: ac97_reg_base + GCR) | (GCR_ACLINK_OFF), addr: ac97_reg_base + GCR); |
311 | clk_disable_unprepare(clk: ac97_clk); |
312 | return 0; |
313 | } |
314 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend); |
315 | |
316 | int pxa2xx_ac97_hw_resume(void) |
317 | { |
318 | clk_prepare_enable(clk: ac97_clk); |
319 | return 0; |
320 | } |
321 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); |
322 | #endif |
323 | |
324 | int pxa2xx_ac97_hw_probe(struct platform_device *dev) |
325 | { |
326 | int ret; |
327 | int irq; |
328 | pxa2xx_audio_ops_t *pdata = dev->dev.platform_data; |
329 | |
330 | ac97_reg_base = devm_platform_ioremap_resource(pdev: dev, index: 0); |
331 | if (IS_ERR(ptr: ac97_reg_base)) { |
332 | dev_err(&dev->dev, "Missing MMIO resource\n" ); |
333 | return PTR_ERR(ptr: ac97_reg_base); |
334 | } |
335 | |
336 | if (pdata) { |
337 | switch (pdata->reset_gpio) { |
338 | case 95: |
339 | case 113: |
340 | reset_gpio = pdata->reset_gpio; |
341 | break; |
342 | case 0: |
343 | reset_gpio = 113; |
344 | break; |
345 | case -1: |
346 | break; |
347 | default: |
348 | dev_err(&dev->dev, "Invalid reset GPIO %d\n" , |
349 | pdata->reset_gpio); |
350 | } |
351 | } else if (!pdata && dev->dev.of_node) { |
352 | pdata = devm_kzalloc(dev: &dev->dev, size: sizeof(*pdata), GFP_KERNEL); |
353 | if (!pdata) |
354 | return -ENOMEM; |
355 | pdata->reset_gpio = of_get_named_gpio(np: dev->dev.of_node, |
356 | list_name: "reset-gpios" , index: 0); |
357 | if (pdata->reset_gpio == -ENOENT) |
358 | pdata->reset_gpio = -1; |
359 | else if (pdata->reset_gpio < 0) |
360 | return pdata->reset_gpio; |
361 | reset_gpio = pdata->reset_gpio; |
362 | } else { |
363 | if (cpu_is_pxa27x()) |
364 | reset_gpio = 113; |
365 | } |
366 | |
367 | if (cpu_is_pxa27x()) { |
368 | /* |
369 | * This gpio is needed for a work-around to a bug in the ac97 |
370 | * controller during warm reset. The direction and level is set |
371 | * here so that it is an output driven high when switching from |
372 | * AC97_nRESET alt function to generic gpio. |
373 | */ |
374 | ret = gpio_request_one(gpio: reset_gpio, GPIOF_OUT_INIT_HIGH, |
375 | label: "pxa27x ac97 reset" ); |
376 | if (ret < 0) { |
377 | pr_err("%s: gpio_request_one() failed: %d\n" , |
378 | __func__, ret); |
379 | goto err_conf; |
380 | } |
381 | pxa27x_configure_ac97reset(reset_gpio, to_gpio: false); |
382 | |
383 | ac97conf_clk = clk_get(dev: &dev->dev, id: "AC97CONFCLK" ); |
384 | if (IS_ERR(ptr: ac97conf_clk)) { |
385 | ret = PTR_ERR(ptr: ac97conf_clk); |
386 | ac97conf_clk = NULL; |
387 | goto err_conf; |
388 | } |
389 | } |
390 | |
391 | ac97_clk = clk_get(dev: &dev->dev, id: "AC97CLK" ); |
392 | if (IS_ERR(ptr: ac97_clk)) { |
393 | ret = PTR_ERR(ptr: ac97_clk); |
394 | ac97_clk = NULL; |
395 | goto err_clk; |
396 | } |
397 | |
398 | ret = clk_prepare_enable(clk: ac97_clk); |
399 | if (ret) |
400 | goto err_clk2; |
401 | |
402 | irq = platform_get_irq(dev, 0); |
403 | if (irq < 0) { |
404 | ret = irq; |
405 | goto err_irq; |
406 | } |
407 | |
408 | ret = request_irq(irq, handler: pxa2xx_ac97_irq, flags: 0, name: "AC97" , NULL); |
409 | if (ret < 0) |
410 | goto err_irq; |
411 | |
412 | return 0; |
413 | |
414 | err_irq: |
415 | writel(readl(addr: ac97_reg_base + GCR) | (GCR_ACLINK_OFF), addr: ac97_reg_base + GCR); |
416 | err_clk2: |
417 | clk_put(clk: ac97_clk); |
418 | ac97_clk = NULL; |
419 | err_clk: |
420 | if (ac97conf_clk) { |
421 | clk_put(clk: ac97conf_clk); |
422 | ac97conf_clk = NULL; |
423 | } |
424 | err_conf: |
425 | return ret; |
426 | } |
427 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); |
428 | |
429 | void pxa2xx_ac97_hw_remove(struct platform_device *dev) |
430 | { |
431 | if (cpu_is_pxa27x()) |
432 | gpio_free(gpio: reset_gpio); |
433 | writel(readl(addr: ac97_reg_base + GCR) | (GCR_ACLINK_OFF), addr: ac97_reg_base + GCR); |
434 | free_irq(platform_get_irq(dev, 0), NULL); |
435 | if (ac97conf_clk) { |
436 | clk_put(clk: ac97conf_clk); |
437 | ac97conf_clk = NULL; |
438 | } |
439 | clk_disable_unprepare(clk: ac97_clk); |
440 | clk_put(clk: ac97_clk); |
441 | ac97_clk = NULL; |
442 | } |
443 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove); |
444 | |
445 | u32 pxa2xx_ac97_read_modr(void) |
446 | { |
447 | if (!ac97_reg_base) |
448 | return 0; |
449 | |
450 | return readl(addr: ac97_reg_base + MODR); |
451 | } |
452 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_modr); |
453 | |
454 | u32 pxa2xx_ac97_read_misr(void) |
455 | { |
456 | if (!ac97_reg_base) |
457 | return 0; |
458 | |
459 | return readl(addr: ac97_reg_base + MISR); |
460 | } |
461 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_read_misr); |
462 | |
463 | MODULE_AUTHOR("Nicolas Pitre" ); |
464 | MODULE_DESCRIPTION("Intel/Marvell PXA sound library" ); |
465 | MODULE_LICENSE("GPL" ); |
466 | |
467 | |