Blame view

sound/arm/pxa2xx-ac97-lib.c 8.31 KB
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * Based on sound/arm/pxa2xx-ac97.c and sound/soc/pxa/pxa2xx-ac97.c
   * which contain:
   *
   * Author:	Nicolas Pitre
   * Created:	Dec 02, 2004
   * Copyright:	MontaVista Software Inc.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/kernel.h>
  #include <linux/platform_device.h>
  #include <linux/interrupt.h>
  #include <linux/clk.h>
  #include <linux/delay.h>
da155d5b4   Paul Gortmaker   sound: Add module...
19
  #include <linux/module.h>
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
20
21
22
23
24
  
  #include <sound/ac97_codec.h>
  #include <sound/pxa2xx-lib.h>
  
  #include <asm/irq.h>
1f017a996   Eric Miao   [ARM] pxa: move A...
25
  #include <mach/regs-ac97.h>
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
26
27
28
29
30
31
  #include <mach/audio.h>
  
  static DEFINE_MUTEX(car_mutex);
  static DECLARE_WAIT_QUEUE_HEAD(gsr_wq);
  static volatile long gsr_bits;
  static struct clk *ac97_clk;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
32
  static struct clk *ac97conf_clk;
26ade896b   Robert Jarzmik   ASoC: Allow choic...
33
  static int reset_gpio;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
34

fb1bf8cd1   Eric Miao   [ARM] pxa: introd...
35
  extern void pxa27x_assert_ac97reset(int reset_gpio, int on);
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  /*
   * Beware PXA27x bugs:
   *
   *   o Slot 12 read from modem space will hang controller.
   *   o CDONE, SDONE interrupt fails after any slot 12 IO.
   *
   * We therefore have an hybrid approach for waiting on SDONE (interrupt or
   * 1 jiffy timeout if interrupt never comes).
   */
  
  unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
  {
  	unsigned short val = -1;
  	volatile u32 *reg_addr;
  
  	mutex_lock(&car_mutex);
  
  	/* set up primary or secondary codec space */
8825e8e8d   Marc Zyngier   ALSA: Fix pxa2xx-...
54
  	if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
55
56
57
  		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
  	else
  		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  	reg_addr += (reg >> 1);
  
  	/* start read access across the ac97 link */
  	GSR = GSR_CDONE | GSR_SDONE;
  	gsr_bits = 0;
  	val = *reg_addr;
  	if (reg == AC97_GPIO_STATUS)
  		goto out;
  	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 &&
  	    !((GSR | gsr_bits) & GSR_SDONE)) {
  		printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)
  ",
  				__func__, reg, GSR | gsr_bits);
  		val = -1;
  		goto out;
  	}
  
  	/* valid data now */
  	GSR = GSR_CDONE | GSR_SDONE;
  	gsr_bits = 0;
  	val = *reg_addr;
  	/* but we've just started another cycle... */
  	wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
  
  out:	mutex_unlock(&car_mutex);
  	return val;
  }
  EXPORT_SYMBOL_GPL(pxa2xx_ac97_read);
  
  void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
  			unsigned short val)
  {
  	volatile u32 *reg_addr;
  
  	mutex_lock(&car_mutex);
  
  	/* set up primary or secondary codec space */
8825e8e8d   Marc Zyngier   ALSA: Fix pxa2xx-...
95
  	if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
96
97
98
  		reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
  	else
  		reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  	reg_addr += (reg >> 1);
  
  	GSR = GSR_CDONE | GSR_SDONE;
  	gsr_bits = 0;
  	*reg_addr = val;
  	if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
  	    !((GSR | gsr_bits) & GSR_CDONE))
  		printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)
  ",
  				__func__, reg, GSR | gsr_bits);
  
  	mutex_unlock(&car_mutex);
  }
  EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
113
114
  #ifdef CONFIG_PXA25x
  static inline void pxa_ac97_warm_pxa25x(void)
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
115
  {
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
116
  	gsr_bits = 0;
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  	GCR |= GCR_WARM_RST | GCR_PRIRDY_IEN | GCR_SECRDY_IEN;
  	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
  }
  
  static inline void pxa_ac97_cold_pxa25x(void)
  {
  	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
  	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
  
  	gsr_bits = 0;
  
  	GCR = GCR_COLD_RST;
  	GCR |= GCR_CDONE_IE|GCR_SDONE_IE;
  	wait_event_timeout(gsr_wq, gsr_bits & (GSR_PCR | GSR_SCR), 1);
  }
  #endif
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
133
  #ifdef CONFIG_PXA27x
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
134
135
136
  static inline void pxa_ac97_warm_pxa27x(void)
  {
  	gsr_bits = 0;
fb1bf8cd1   Eric Miao   [ARM] pxa: introd...
137
138
  	/* warm reset broken on Bulverde, so manually keep AC97 reset high */
  	pxa27x_assert_ac97reset(reset_gpio, 1);
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
139
140
  	udelay(10);
  	GCR |= GCR_WARM_RST;
fb1bf8cd1   Eric Miao   [ARM] pxa: introd...
141
  	pxa27x_assert_ac97reset(reset_gpio, 0);
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
142
  	udelay(500);
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  }
  
  static inline void pxa_ac97_cold_pxa27x(void)
  {
  	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
  	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
  
  	gsr_bits = 0;
  
  	/* PXA27x Developers Manual section 13.5.2.2.1 */
  	clk_enable(ac97conf_clk);
  	udelay(5);
  	clk_disable(ac97conf_clk);
  	GCR = GCR_COLD_RST;
  	udelay(50);
  }
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
159
  #endif
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
160
161
162
163
  #ifdef CONFIG_PXA3xx
  static inline void pxa_ac97_warm_pxa3xx(void)
  {
  	int timeout = 100;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
164

9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
165
  	gsr_bits = 0;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
166

9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
167
168
169
170
  	/* Can't use interrupts */
  	GCR |= GCR_WARM_RST;
  	while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
  		mdelay(1);
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
171
  }
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
172

9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
173
  static inline void pxa_ac97_cold_pxa3xx(void)
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
174
  {
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
175
176
177
178
179
180
181
  	int timeout = 1000;
  
  	/* Hold CLKBPB for 100us */
  	GCR = 0;
  	GCR = GCR_CLKBPB;
  	udelay(100);
  	GCR = 0;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
182
183
184
185
186
  
  	GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
  	GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
  
  	gsr_bits = 0;
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
187

9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
188
189
190
191
192
193
  	/* Can't use interrupts on PXA3xx */
  	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
  
  	GCR = GCR_WARM_RST | GCR_COLD_RST;
  	while (!(GSR & (GSR_PCR | GSR_SCR)) && timeout--)
  		mdelay(10);
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
194
195
196
197
198
  }
  #endif
  
  bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
  {
057de50c0   Luotao Fu   pxa2xx-ac97: fix ...
199
  	unsigned long gsr;
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
200
  #ifdef CONFIG_PXA25x
8825e8e8d   Marc Zyngier   ALSA: Fix pxa2xx-...
201
  	if (cpu_is_pxa25x())
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
202
203
  		pxa_ac97_warm_pxa25x();
  	else
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
204
  #endif
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
205
206
207
208
209
210
211
212
213
214
215
  #ifdef CONFIG_PXA27x
  	if (cpu_is_pxa27x())
  		pxa_ac97_warm_pxa27x();
  	else
  #endif
  #ifdef CONFIG_PXA3xx
  	if (cpu_is_pxa3xx())
  		pxa_ac97_warm_pxa3xx();
  	else
  #endif
  		BUG();
057de50c0   Luotao Fu   pxa2xx-ac97: fix ...
216
217
  	gsr = GSR | gsr_bits;
  	if (!(gsr & (GSR_PCR | GSR_SCR))) {
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
218
219
  		printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)
  ",
057de50c0   Luotao Fu   pxa2xx-ac97: fix ...
220
  				 __func__, gsr);
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
221
222
223
224
225
226
227
228
229
230
  
  		return false;
  	}
  
  	return true;
  }
  EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
  
  bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
  {
057de50c0   Luotao Fu   pxa2xx-ac97: fix ...
231
  	unsigned long gsr;
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
232
  #ifdef CONFIG_PXA25x
8825e8e8d   Marc Zyngier   ALSA: Fix pxa2xx-...
233
  	if (cpu_is_pxa25x())
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  		pxa_ac97_cold_pxa25x();
  	else
  #endif
  #ifdef CONFIG_PXA27x
  	if (cpu_is_pxa27x())
  		pxa_ac97_cold_pxa27x();
  	else
  #endif
  #ifdef CONFIG_PXA3xx
  	if (cpu_is_pxa3xx())
  		pxa_ac97_cold_pxa3xx();
  	else
  #endif
  		BUG();
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
248

057de50c0   Luotao Fu   pxa2xx-ac97: fix ...
249
250
  	gsr = GSR | gsr_bits;
  	if (!(gsr & (GSR_PCR | GSR_SCR))) {
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
251
252
  		printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)
  ",
057de50c0   Luotao Fu   pxa2xx-ac97: fix ...
253
  				 __func__, gsr);
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  
  		return false;
  	}
  
  	return true;
  }
  EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset);
  
  
  void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97)
  {
  	GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
  	GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
  }
  EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset);
  
  static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
  {
  	long status;
  
  	status = GSR;
  	if (status) {
  		GSR = status;
  		gsr_bits |= status;
  		wake_up(&gsr_wq);
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
279
280
281
  		/* Although we don't use those we still need to clear them
  		   since they tend to spuriously trigger when MMC is used
  		   (hardware bug? go figure)... */
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
282
283
284
285
286
  		if (cpu_is_pxa27x()) {
  			MISR = MISR_EOC;
  			PISR = PISR_EOC;
  			MCSR = MCSR_EOC;
  		}
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  
  		return IRQ_HANDLED;
  	}
  
  	return IRQ_NONE;
  }
  
  #ifdef CONFIG_PM
  int pxa2xx_ac97_hw_suspend(void)
  {
  	GCR |= GCR_ACLINK_OFF;
  	clk_disable(ac97_clk);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend);
  
  int pxa2xx_ac97_hw_resume(void)
  {
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
305
306
307
308
309
310
311
312
313
  	clk_enable(ac97_clk);
  	return 0;
  }
  EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume);
  #endif
  
  int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
  {
  	int ret;
eae17754a   Mark Brown   [ARM] pxa: merge ...
314
  	pxa2xx_audio_ops_t *pdata = dev->dev.platform_data;
26ade896b   Robert Jarzmik   ASoC: Allow choic...
315
316
317
318
319
320
321
322
323
324
325
326
327
  
  	if (pdata) {
  		switch (pdata->reset_gpio) {
  		case 95:
  		case 113:
  			reset_gpio = pdata->reset_gpio;
  			break;
  		case 0:
  			reset_gpio = 113;
  			break;
  		case -1:
  			break;
  		default:
1f2186951   Takashi Iwai   ALSA: Fix wrong p...
328
329
  			dev_err(&dev->dev, "Invalid reset GPIO %d
  ",
26ade896b   Robert Jarzmik   ASoC: Allow choic...
330
331
332
333
334
335
  				pdata->reset_gpio);
  		}
  	} else {
  		if (cpu_is_pxa27x())
  			reset_gpio = 113;
  	}
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
336

9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
337
338
  	if (cpu_is_pxa27x()) {
  		/* Use GPIO 113 as AC97 Reset on Bulverde */
fb1bf8cd1   Eric Miao   [ARM] pxa: introd...
339
  		pxa27x_assert_ac97reset(reset_gpio, 0);
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
340
341
342
343
  		ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
  		if (IS_ERR(ac97conf_clk)) {
  			ret = PTR_ERR(ac97conf_clk);
  			ac97conf_clk = NULL;
796123368   Dmitry Eremin-Solenikov   pxa2xx-ac97: swit...
344
  			goto err_conf;
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
345
  		}
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
346
  	}
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
347
348
349
350
351
  
  	ac97_clk = clk_get(&dev->dev, "AC97CLK");
  	if (IS_ERR(ac97_clk)) {
  		ret = PTR_ERR(ac97_clk);
  		ac97_clk = NULL;
796123368   Dmitry Eremin-Solenikov   pxa2xx-ac97: swit...
352
  		goto err_clk;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
353
  	}
796123368   Dmitry Eremin-Solenikov   pxa2xx-ac97: swit...
354
355
356
  	ret = clk_enable(ac97_clk);
  	if (ret)
  		goto err_clk2;
88e24c3a4   Yong Zhang   sound: irq: Remov...
357
  	ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
796123368   Dmitry Eremin-Solenikov   pxa2xx-ac97: swit...
358
359
360
361
  	if (ret < 0)
  		goto err_irq;
  
  	return 0;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
362
363
364
  
  err_irq:
  	GCR |= GCR_ACLINK_OFF;
796123368   Dmitry Eremin-Solenikov   pxa2xx-ac97: swit...
365
366
367
368
  err_clk2:
  	clk_put(ac97_clk);
  	ac97_clk = NULL;
  err_clk:
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
369
370
371
372
  	if (ac97conf_clk) {
  		clk_put(ac97conf_clk);
  		ac97conf_clk = NULL;
  	}
796123368   Dmitry Eremin-Solenikov   pxa2xx-ac97: swit...
373
  err_conf:
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
374
375
376
377
378
379
380
381
  	return ret;
  }
  EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);
  
  void pxa2xx_ac97_hw_remove(struct platform_device *dev)
  {
  	GCR |= GCR_ACLINK_OFF;
  	free_irq(IRQ_AC97, NULL);
9d1cf39be   Dmitry Eremin-Solenikov   ALSA: pxa2xx-ac97...
382
383
384
385
  	if (ac97conf_clk) {
  		clk_put(ac97conf_clk);
  		ac97conf_clk = NULL;
  	}
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
386
387
388
389
390
391
392
393
394
  	clk_disable(ac97_clk);
  	clk_put(ac97_clk);
  	ac97_clk = NULL;
  }
  EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove);
  
  MODULE_AUTHOR("Nicolas Pitre");
  MODULE_DESCRIPTION("Intel/Marvell PXA sound library");
  MODULE_LICENSE("GPL");