~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/arm/pxa2xx-ac97-lib.c

Version: ~ [ linux-5.1-rc5 ] ~ [ linux-5.0.7 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.34 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.111 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.168 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.178 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.138 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.65 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 #include <linux/module.h>
 20 #include <linux/io.h>
 21 #include <linux/gpio.h>
 22 
 23 #include <sound/pxa2xx-lib.h>
 24 
 25 #include <mach/irqs.h>
 26 #include <mach/regs-ac97.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 static struct clk *ac97conf_clk;
 34 static int reset_gpio;
 35 
 36 extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio);
 37 
 38 /*
 39  * Beware PXA27x bugs:
 40  *
 41  *   o Slot 12 read from modem space will hang controller.
 42  *   o CDONE, SDONE interrupt fails after any slot 12 IO.
 43  *
 44  * We therefore have an hybrid approach for waiting on SDONE (interrupt or
 45  * 1 jiffy timeout if interrupt never comes).
 46  */
 47 
 48 int pxa2xx_ac97_read(int slot, unsigned short reg)
 49 {
 50         int val = -ENODEV;
 51         volatile u32 *reg_addr;
 52 
 53         if (slot > 0)
 54                 return -ENODEV;
 55 
 56         mutex_lock(&car_mutex);
 57 
 58         /* set up primary or secondary codec space */
 59         if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
 60                 reg_addr = slot ? &SMC_REG_BASE : &PMC_REG_BASE;
 61         else
 62                 reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE;
 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 & 0xffff);
 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 = -ETIMEDOUT;
 76                 goto out;
 77         }
 78 
 79         /* valid data now */
 80         GSR = GSR_CDONE | GSR_SDONE;
 81         gsr_bits = 0;
 82         val = (*reg_addr & 0xffff);
 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 int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val)
 92 {
 93         volatile u32 *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 = slot ? &SMC_REG_BASE : &PMC_REG_BASE;
101         else
102                 reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE;
103         reg_addr += (reg >> 1);
104 
105         GSR = GSR_CDONE | GSR_SDONE;
106         gsr_bits = 0;
107         *reg_addr = val;
108         if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
109             !((GSR | gsr_bits) & GSR_CDONE)) {
110                 printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
111                                 __func__, reg, GSR | gsr_bits);
112                 ret = -EIO;
113         }
114 
115         mutex_unlock(&car_mutex);
116         return ret;
117 }
118 EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);
119 
120 #ifdef CONFIG_PXA25x
121 static inline void pxa_ac97_warm_pxa25x(void)
122 {
123         gsr_bits = 0;
124 
125         GCR |= GCR_WARM_RST;
126 }
127 
128 static inline void pxa_ac97_cold_pxa25x(void)
129 {
130         GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
131         GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
132 
133         gsr_bits = 0;
134 
135         GCR = GCR_COLD_RST;
136 }
137 #endif
138 
139 #ifdef CONFIG_PXA27x
140 static inline void pxa_ac97_warm_pxa27x(void)
141 {
142         gsr_bits = 0;
143 
144         /* warm reset broken on Bulverde, so manually keep AC97 reset high */
145         pxa27x_configure_ac97reset(reset_gpio, true);
146         udelay(10);
147         GCR |= GCR_WARM_RST;
148         pxa27x_configure_ac97reset(reset_gpio, false);
149         udelay(500);
150 }
151 
152 static inline void pxa_ac97_cold_pxa27x(void)
153 {
154         GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
155         GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
156 
157         gsr_bits = 0;
158 
159         /* PXA27x Developers Manual section 13.5.2.2.1 */
160         clk_prepare_enable(ac97conf_clk);
161         udelay(5);
162         clk_disable_unprepare(ac97conf_clk);
163         GCR = GCR_COLD_RST | GCR_WARM_RST;
164 }
165 #endif
166 
167 #ifdef CONFIG_PXA3xx
168 static inline void pxa_ac97_warm_pxa3xx(void)
169 {
170         gsr_bits = 0;
171 
172         /* Can't use interrupts */
173         GCR |= GCR_WARM_RST;
174 }
175 
176 static inline void pxa_ac97_cold_pxa3xx(void)
177 {
178         /* Hold CLKBPB for 100us */
179         GCR = 0;
180         GCR = GCR_CLKBPB;
181         udelay(100);
182         GCR = 0;
183 
184         GCR &=  GCR_COLD_RST;  /* clear everything but nCRST */
185         GCR &= ~GCR_COLD_RST;  /* then assert nCRST */
186 
187         gsr_bits = 0;
188 
189         /* Can't use interrupts on PXA3xx */
190         GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
191 
192         GCR = GCR_WARM_RST | GCR_COLD_RST;
193 }
194 #endif
195 
196 bool pxa2xx_ac97_try_warm_reset(void)
197 {
198         unsigned long gsr;
199         unsigned int timeout = 100;
200 
201 #ifdef CONFIG_PXA25x
202         if (cpu_is_pxa25x())
203                 pxa_ac97_warm_pxa25x();
204         else
205 #endif
206 #ifdef CONFIG_PXA27x
207         if (cpu_is_pxa27x())
208                 pxa_ac97_warm_pxa27x();
209         else
210 #endif
211 #ifdef CONFIG_PXA3xx
212         if (cpu_is_pxa3xx())
213                 pxa_ac97_warm_pxa3xx();
214         else
215 #endif
216                 snd_BUG();
217 
218         while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
219                 mdelay(1);
220 
221         gsr = GSR | gsr_bits;
222         if (!(gsr & (GSR_PCR | GSR_SCR))) {
223                 printk(KERN_INFO "%s: warm reset timeout (GSR=%#lx)\n",
224                                  __func__, gsr);
225 
226                 return false;
227         }
228 
229         return true;
230 }
231 EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
232 
233 bool pxa2xx_ac97_try_cold_reset(void)
234 {
235         unsigned long gsr;
236         unsigned int timeout = 1000;
237 
238 #ifdef CONFIG_PXA25x
239         if (cpu_is_pxa25x())
240                 pxa_ac97_cold_pxa25x();
241         else
242 #endif
243 #ifdef CONFIG_PXA27x
244         if (cpu_is_pxa27x())
245                 pxa_ac97_cold_pxa27x();
246         else
247 #endif
248 #ifdef CONFIG_PXA3xx
249         if (cpu_is_pxa3xx())
250                 pxa_ac97_cold_pxa3xx();
251         else
252 #endif
253                 snd_BUG();
254 
255         while (!((GSR | gsr_bits) & (GSR_PCR | GSR_SCR)) && timeout--)
256                 mdelay(1);
257 
258         gsr = GSR | gsr_bits;
259         if (!(gsr & (GSR_PCR | GSR_SCR))) {
260                 printk(KERN_INFO "%s: cold reset timeout (GSR=%#lx)\n",
261                                  __func__, gsr);
262 
263                 return false;
264         }
265 
266         return true;
267 }
268 EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset);
269 
270 
271 void pxa2xx_ac97_finish_reset(void)
272 {
273         GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
274         GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
275 }
276 EXPORT_SYMBOL_GPL(pxa2xx_ac97_finish_reset);
277 
278 static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
279 {
280         long status;
281 
282         status = GSR;
283         if (status) {
284                 GSR = status;
285                 gsr_bits |= status;
286                 wake_up(&gsr_wq);
287 
288                 /* Although we don't use those we still need to clear them
289                    since they tend to spuriously trigger when MMC is used
290                    (hardware bug? go figure)... */
291                 if (cpu_is_pxa27x()) {
292                         MISR = MISR_EOC;
293                         PISR = PISR_EOC;
294                         MCSR = MCSR_EOC;
295                 }
296 
297                 return IRQ_HANDLED;
298         }
299 
300         return IRQ_NONE;
301 }
302 
303 #ifdef CONFIG_PM
304 int pxa2xx_ac97_hw_suspend(void)
305 {
306         GCR |= GCR_ACLINK_OFF;
307         clk_disable_unprepare(ac97_clk);
308         return 0;
309 }
310 EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend);
311 
312 int pxa2xx_ac97_hw_resume(void)
313 {
314         clk_prepare_enable(ac97_clk);
315         return 0;
316 }
317 EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_resume);
318 #endif
319 
320 int pxa2xx_ac97_hw_probe(struct platform_device *dev)
321 {
322         int ret;
323         pxa2xx_audio_ops_t *pdata = dev->dev.platform_data;
324 
325         if (pdata) {
326                 switch (pdata->reset_gpio) {
327                 case 95:
328                 case 113:
329                         reset_gpio = pdata->reset_gpio;
330                         break;
331                 case 0:
332                         reset_gpio = 113;
333                         break;
334                 case -1:
335                         break;
336                 default:
337                         dev_err(&dev->dev, "Invalid reset GPIO %d\n",
338                                 pdata->reset_gpio);
339                 }
340         } else {
341                 if (cpu_is_pxa27x())
342                         reset_gpio = 113;
343         }
344 
345         if (cpu_is_pxa27x()) {
346                 /*
347                  * This gpio is needed for a work-around to a bug in the ac97
348                  * controller during warm reset.  The direction and level is set
349                  * here so that it is an output driven high when switching from
350                  * AC97_nRESET alt function to generic gpio.
351                  */
352                 ret = gpio_request_one(reset_gpio, GPIOF_OUT_INIT_HIGH,
353                                        "pxa27x ac97 reset");
354                 if (ret < 0) {
355                         pr_err("%s: gpio_request_one() failed: %d\n",
356                                __func__, ret);
357                         goto err_conf;
358                 }
359                 pxa27x_configure_ac97reset(reset_gpio, false);
360 
361                 ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK");
362                 if (IS_ERR(ac97conf_clk)) {
363                         ret = PTR_ERR(ac97conf_clk);
364                         ac97conf_clk = NULL;
365                         goto err_conf;
366                 }
367         }
368 
369         ac97_clk = clk_get(&dev->dev, "AC97CLK");
370         if (IS_ERR(ac97_clk)) {
371                 ret = PTR_ERR(ac97_clk);
372                 ac97_clk = NULL;
373                 goto err_clk;
374         }
375 
376         ret = clk_prepare_enable(ac97_clk);
377         if (ret)
378                 goto err_clk2;
379 
380         ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
381         if (ret < 0)
382                 goto err_irq;
383 
384         return 0;
385 
386 err_irq:
387         GCR |= GCR_ACLINK_OFF;
388 err_clk2:
389         clk_put(ac97_clk);
390         ac97_clk = NULL;
391 err_clk:
392         if (ac97conf_clk) {
393                 clk_put(ac97conf_clk);
394                 ac97conf_clk = NULL;
395         }
396 err_conf:
397         return ret;
398 }
399 EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_probe);
400 
401 void pxa2xx_ac97_hw_remove(struct platform_device *dev)
402 {
403         if (cpu_is_pxa27x())
404                 gpio_free(reset_gpio);
405         GCR |= GCR_ACLINK_OFF;
406         free_irq(IRQ_AC97, NULL);
407         if (ac97conf_clk) {
408                 clk_put(ac97conf_clk);
409                 ac97conf_clk = NULL;
410         }
411         clk_disable_unprepare(ac97_clk);
412         clk_put(ac97_clk);
413         ac97_clk = NULL;
414 }
415 EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_remove);
416 
417 MODULE_AUTHOR("Nicolas Pitre");
418 MODULE_DESCRIPTION("Intel/Marvell PXA sound library");
419 MODULE_LICENSE("GPL");
420 
421 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp