diff options
Diffstat (limited to 'sound/arm/pxa2xx-ac97-lib.c')
-rw-r--r-- | sound/arm/pxa2xx-ac97-lib.c | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c new file mode 100644 index 000000000000..95f8ead44f2a --- /dev/null +++ b/sound/arm/pxa2xx-ac97-lib.c | |||
@@ -0,0 +1,325 @@ | |||
1 | /* | ||
2 | * Based on sound/arm/pxa2xx-ac97.c and sound/soc/pxa/pxa2xx-ac97.c | ||
3 | * which contain: | ||
4 | * | ||
5 | * Author: Nicolas Pitre | ||
6 | * Created: Dec 02, 2004 | ||
7 | * Copyright: MontaVista Software Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/clk.h> | ||
18 | #include <linux/delay.h> | ||
19 | |||
20 | #include <sound/ac97_codec.h> | ||
21 | #include <sound/pxa2xx-lib.h> | ||
22 | |||
23 | #include <asm/irq.h> | ||
24 | #include <mach/hardware.h> | ||
25 | #include <mach/pxa-regs.h> | ||
26 | #include <mach/pxa2xx-gpio.h> | ||
27 | #include <mach/audio.h> | ||
28 | |||
29 | static DEFINE_MUTEX(car_mutex); | ||
30 | static DECLARE_WAIT_QUEUE_HEAD(gsr_wq); | ||
31 | static volatile long gsr_bits; | ||
32 | static struct clk *ac97_clk; | ||
33 | #ifdef CONFIG_PXA27x | ||
34 | static struct clk *ac97conf_clk; | ||
35 | #endif | ||
36 | |||
37 | /* | ||
38 | * Beware PXA27x bugs: | ||
39 | * | ||
40 | * o Slot 12 read from modem space will hang controller. | ||
41 | * o CDONE, SDONE interrupt fails after any slot 12 IO. | ||
42 | * | ||
43 | * We therefore have an hybrid approach for waiting on SDONE (interrupt or | ||
44 | * 1 jiffy timeout if interrupt never comes). | ||
45 | */ | ||
46 | |||
47 | unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | ||
48 | { | ||
49 | unsigned short val = -1; | ||
50 | volatile u32 *reg_addr; | ||
51 | |||
52 | mutex_lock(&car_mutex); | ||
53 | |||
54 | /* set up primary or secondary codec space */ | ||
55 | #if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) | ||
56 | reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
57 | #else | ||
58 | if (reg == AC97_GPIO_STATUS) | ||
59 | reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; | ||
60 | else | ||
61 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
62 | #endif | ||
63 | reg_addr += (reg >> 1); | ||
64 | |||
65 | /* start read access across the ac97 link */ | ||
66 | GSR = GSR_CDONE | GSR_SDONE; | ||
67 | gsr_bits = 0; | ||
68 | val = *reg_addr; | ||
69 | if (reg == AC97_GPIO_STATUS) | ||
70 | goto out; | ||
71 | if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 && | ||
72 | !((GSR | gsr_bits) & GSR_SDONE)) { | ||
73 | printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n", | ||
74 | __func__, reg, GSR | gsr_bits); | ||
75 | val = -1; | ||
76 | goto out; | ||
77 | } | ||
78 | |||
79 | /* valid data now */ | ||
80 | GSR = GSR_CDONE | GSR_SDONE; | ||
81 | gsr_bits = 0; | ||
82 | val = *reg_addr; | ||
83 | /* but we've just started another cycle... */ | ||
84 | wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1); | ||
85 | |||
86 | out: mutex_unlock(&car_mutex); | ||
87 | return val; | ||
88 | } | ||
89 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_read); | ||
90 | |||
91 | void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | ||
92 | unsigned short val) | ||
93 | { | ||
94 | volatile u32 *reg_addr; | ||
95 | |||
96 | mutex_lock(&car_mutex); | ||
97 | |||
98 | /* set up primary or secondary codec space */ | ||
99 | #if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) | ||
100 | reg_addr = (ac97->num & 1) ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
101 | #else | ||
102 | if (reg == AC97_GPIO_STATUS) | ||
103 | reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE; | ||
104 | else | ||
105 | reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE; | ||
106 | #endif | ||
107 | reg_addr += (reg >> 1); | ||
108 | |||
109 | GSR = GSR_CDONE | GSR_SDONE; | ||
110 | gsr_bits = 0; | ||
111 | *reg_addr = val; | ||
112 | if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 && | ||
113 | !((GSR | gsr_bits) & GSR_CDONE)) | ||
114 | printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n", | ||
115 | __func__, reg, GSR | gsr_bits); | ||
116 | |||
117 | mutex_unlock(&car_mutex); | ||
118 | } | ||
119 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_write); | ||
120 | |||
121 | bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97) | ||
122 | { | ||
123 | #ifdef CONFIG_PXA3xx | ||
124 | int timeout = 100; | ||
125 | #endif | ||
126 | gsr_bits = 0; | ||
127 | |||
128 | #ifdef CONFIG_PXA27x | ||
129 | /* warm reset broken on Bulverde, | ||
130 | so manually keep AC97 reset high */ | ||
131 | pxa_gpio_mode(113 | GPIO_OUT | GPIO_DFLT_HIGH); | ||
132 | udelay(10); | ||
133 | GCR |= GCR_WARM_RST; | ||
134 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | ||
135 | udelay(500); | ||
136 | #elif defined(CONFIG_PXA3xx) | ||
137 | /* Can't use interrupts */ | ||
138 | GCR |= GCR_WARM_RST; | ||
139 | while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--) | ||
140 | mdelay(1); | ||
141 | #else | ||
142 | GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN; | ||
143 | wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); | ||
144 | #endif | ||
145 | |||
146 | if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) { | ||
147 | printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n", | ||
148 | __func__, gsr_bits); | ||
149 | |||
150 | return false; | ||
151 | } | ||
152 | |||
153 | return true; | ||
154 | } | ||
155 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset); | ||
156 | |||
157 | bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97) | ||
158 | { | ||
159 | #ifdef CONFIG_PXA3xx | ||
160 | int timeout = 1000; | ||
161 | |||
162 | /* Hold CLKBPB for 100us */ | ||
163 | GCR = 0; | ||
164 | GCR = GCR_CLKBPB; | ||
165 | udelay(100); | ||
166 | GCR = 0; | ||
167 | #endif | ||
168 | |||
169 | GCR &= GCR_COLD_RST; /* clear everything but nCRST */ | ||
170 | GCR &= ~GCR_COLD_RST; /* then assert nCRST */ | ||
171 | |||
172 | gsr_bits = 0; | ||
173 | #ifdef CONFIG_PXA27x | ||
174 | /* PXA27x Developers Manual section 13.5.2.2.1 */ | ||
175 | clk_enable(ac97conf_clk); | ||
176 | udelay(5); | ||
177 | clk_disable(ac97conf_clk); | ||
178 | GCR = GCR_COLD_RST; | ||
179 | udelay(50); | ||
180 | #elif defined(CONFIG_PXA3xx) | ||
181 | /* Can't use interrupts on PXA3xx */ | ||
182 | GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); | ||
183 | |||
184 | GCR = GCR_WARM_RST | GCR_COLD_RST; | ||
185 | while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--) | ||
186 | mdelay(10); | ||
187 | #else | ||
188 | GCR = GCR_COLD_RST; | ||
189 | GCR |= GCR_CDONE_IE|GCR_SDONE_IE; | ||
190 | wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1); | ||
191 | #endif | ||
192 | |||
193 | if (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR))) { | ||
194 | printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n", | ||
195 | __func__, gsr_bits); | ||
196 | |||
197 | return false; | ||
198 | } | ||
199 | |||
200 | return true; | ||
201 | } | ||
202 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset); | ||
203 | |||
204 | |||
205 | void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97) | ||
206 | { | ||
207 | GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN); | ||
208 | GCR |= GCR_SDONE_IE|GCR_CDONE_IE; | ||
209 | } | ||
210 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset); | ||
211 | |||
212 | static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id) | ||
213 | { | ||
214 | long status; | ||
215 | |||
216 | status = GSR; | ||
217 | if (status) { | ||
218 | GSR = status; | ||
219 | gsr_bits |= status; | ||
220 | wake_up(&gsr_wq); | ||
221 | |||
222 | #ifdef CONFIG_PXA27x | ||
223 | /* Although we don't use those we still need to clear them | ||
224 | since they tend to spuriously trigger when MMC is used | ||
225 | (hardware bug? go figure)... */ | ||
226 | MISR = MISR_EOC; | ||
227 | PISR = PISR_EOC; | ||
228 | MCSR = MCSR_EOC; | ||
229 | #endif | ||
230 | |||
231 | return IRQ_HANDLED; | ||
232 | } | ||
233 | |||
234 | return IRQ_NONE; | ||
235 | } | ||
236 | |||
237 | #ifdef CONFIG_PM | ||
238 | int pxa2xx_ac97_hw_suspend(void) | ||
239 | { | ||
240 | GCR |= GCR_ACLINK_OFF; | ||
241 | clk_disable(ac97_clk); | ||
242 | return 0; | ||
243 | } | ||
244 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend); | ||
245 | |||
246 | int pxa2xx_ac97_hw_resume(void) | ||
247 | { | ||
248 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | ||
249 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); | ||
250 | pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); | ||
251 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); | ||
252 | #ifdef CONFIG_PXA27x | ||
253 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | ||
254 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | ||
255 | #endif | ||
256 | clk_enable(ac97_clk); | ||
257 | return 0; | ||
258 | } | ||
259 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume); | ||
260 | #endif | ||
261 | |||
262 | int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) | ||
263 | { | ||
264 | int ret; | ||
265 | |||
266 | ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL); | ||
267 | if (ret < 0) | ||
268 | goto err; | ||
269 | |||
270 | pxa_gpio_mode(GPIO31_SYNC_AC97_MD); | ||
271 | pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); | ||
272 | pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); | ||
273 | pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); | ||
274 | #ifdef CONFIG_PXA27x | ||
275 | /* Use GPIO 113 as AC97 Reset on Bulverde */ | ||
276 | pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT); | ||
277 | ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); | ||
278 | if (IS_ERR(ac97conf_clk)) { | ||
279 | ret = PTR_ERR(ac97conf_clk); | ||
280 | ac97conf_clk = NULL; | ||
281 | goto err_irq; | ||
282 | } | ||
283 | #endif | ||
284 | |||
285 | ac97_clk = clk_get(&dev->dev, "AC97CLK"); | ||
286 | if (IS_ERR(ac97_clk)) { | ||
287 | ret = PTR_ERR(ac97_clk); | ||
288 | ac97_clk = NULL; | ||
289 | goto err_irq; | ||
290 | } | ||
291 | |||
292 | return clk_enable(ac97_clk); | ||
293 | |||
294 | err_irq: | ||
295 | GCR |= GCR_ACLINK_OFF; | ||
296 | #ifdef CONFIG_PXA27x | ||
297 | if (ac97conf_clk) { | ||
298 | clk_put(ac97conf_clk); | ||
299 | ac97conf_clk = NULL; | ||
300 | } | ||
301 | #endif | ||
302 | free_irq(IRQ_AC97, NULL); | ||
303 | err: | ||
304 | return ret; | ||
305 | } | ||
306 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe); | ||
307 | |||
308 | void pxa2xx_ac97_hw_remove(struct platform_device *dev) | ||
309 | { | ||
310 | GCR |= GCR_ACLINK_OFF; | ||
311 | free_irq(IRQ_AC97, NULL); | ||
312 | #ifdef CONFIG_PXA27x | ||
313 | clk_put(ac97conf_clk); | ||
314 | ac97conf_clk = NULL; | ||
315 | #endif | ||
316 | clk_disable(ac97_clk); | ||
317 | clk_put(ac97_clk); | ||
318 | ac97_clk = NULL; | ||
319 | } | ||
320 | EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove); | ||
321 | |||
322 | MODULE_AUTHOR("Nicolas Pitre"); | ||
323 | MODULE_DESCRIPTION("Intel/Marvell PXA sound library"); | ||
324 | MODULE_LICENSE("GPL"); | ||
325 | |||