This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / arm / mach-pxa / ssp.c
1 /*
2  *  linux/arch/arm/mach-pxa/ssp.c
3  *
4  *  based on linux/arch/arm/mach-sa1100/ssp.c by Russell King
5  *
6  *  Copyright (C) 2003 Russell King.
7  *  Copyright (C) 2003 Wolfson Microelectronics PLC
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  *  PXA2xx SSP driver.  This provides the generic core for simple
14  *  IO-based SSP applications and allows easy port setup for DMA access.
15  *
16  *  Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
17  *
18  *  Revision history:
19  *   22nd Aug 2003 Initial version.
20  *
21  */
22
23 #include <linux/module.h>
24 #include <linux/kernel.h>
25 #include <linux/sched.h>
26 #include <linux/slab.h>
27 #include <linux/errno.h>
28 #include <linux/interrupt.h>
29 #include <linux/ioport.h>
30 #include <linux/init.h>
31 #include <asm/io.h>
32 #include <asm/irq.h>
33 #include <asm/hardware.h>
34 #include <asm/arch/ssp.h>
35 #include <asm/arch/pxa-regs.h>
36
37 static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
38 {
39         struct ssp_dev *dev = (struct ssp_dev*) dev_id;
40         unsigned int status = SSSR_P(dev->port);
41
42         SSSR_P(dev->port) = status; /* clear status bits */
43
44         if (status & SSSR_ROR)
45                 printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port);
46
47         if (status & SSSR_TUR)
48                 printk(KERN_WARNING "SSP(%d): transmitter underrun\n", dev->port);
49
50         if (status & SSSR_BCE)
51                 printk(KERN_WARNING "SSP(%d): bit count error\n", dev->port);
52
53         return IRQ_HANDLED;
54 }
55
56 /**
57  * ssp_write_word - write a word to the SSP port
58  * @data: 32-bit, MSB justified data to write.
59  *
60  * Wait for a free entry in the SSP transmit FIFO, and write a data
61  * word to the SSP port.
62  *
63  * The caller is expected to perform the necessary locking.
64  *
65  * Returns:
66  *   %-ETIMEDOUT        timeout occurred (for future)
67  *   0                  success
68  */
69 int ssp_write_word(struct ssp_dev *dev, u32 data)
70 {
71         while (!(SSSR_P(dev->port) & SSSR_TNF))
72                 cpu_relax();
73
74         SSDR_P(dev->port) = data;
75
76         return 0;
77 }
78
79 /**
80  * ssp_read_word - read a word from the SSP port
81  *
82  * Wait for a data word in the SSP receive FIFO, and return the
83  * received data.  Data is LSB justified.
84  *
85  * Note: Currently, if data is not expected to be received, this
86  * function will wait for ever.
87  *
88  * The caller is expected to perform the necessary locking.
89  *
90  * Returns:
91  *   %-ETIMEDOUT        timeout occurred (for future)
92  *   32-bit data        success
93  */
94 int ssp_read_word(struct ssp_dev *dev)
95 {
96         while (!(SSSR_P(dev->port) & SSSR_RNE))
97                 cpu_relax();
98
99         return SSDR_P(dev->port);
100 }
101
102 /**
103  * ssp_flush - flush the transmit and receive FIFOs
104  *
105  * Wait for the SSP to idle, and ensure that the receive FIFO
106  * is empty.
107  *
108  * The caller is expected to perform the necessary locking.
109  */
110 void ssp_flush(struct ssp_dev *dev)
111 {
112         do {
113                 while (SSSR_P(dev->port) & SSSR_RNE) {
114                         (void) SSDR_P(dev->port);
115                 }
116         } while (SSSR_P(dev->port) & SSSR_BSY);
117 }
118
119 /**
120  * ssp_enable - enable the SSP port
121  *
122  * Turn on the SSP port.
123  */
124 void ssp_enable(struct ssp_dev *dev)
125 {
126         SSCR0_P(dev->port) |= SSCR0_SSE;
127 }
128
129 /**
130  * ssp_disable - shut down the SSP port
131  *
132  * Turn off the SSP port, optionally powering it down.
133  */
134 void ssp_disable(struct ssp_dev *dev)
135 {
136         SSCR0_P(dev->port) &= ~SSCR0_SSE;
137 }
138
139 /**
140  * ssp_save_state - save the SSP configuration
141  * @ssp: pointer to structure to save SSP configuration
142  *
143  * Save the configured SSP state for suspend.
144  */
145 void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp)
146 {
147         ssp->cr0 = SSCR0_P(dev->port);
148         ssp->cr1 = SSCR1_P(dev->port);
149         ssp->to = SSTO_P(dev->port);
150         ssp->psp = SSPSP_P(dev->port);
151
152         SSCR0_P(dev->port) &= ~SSCR0_SSE;
153 }
154
155 /**
156  * ssp_restore_state - restore a previously saved SSP configuration
157  * @ssp: pointer to configuration saved by ssp_save_state
158  *
159  * Restore the SSP configuration saved previously by ssp_save_state.
160  */
161 void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp)
162 {
163         SSSR_P(dev->port) = SSSR_ROR | SSSR_TUR | SSSR_BCE;
164
165         SSCR0_P(dev->port) = ssp->cr0 & ~SSCR0_SSE;
166         SSCR1_P(dev->port) = ssp->cr1;
167         SSTO_P(dev->port) = ssp->to;
168         SSPSP_P(dev->port) = ssp->psp;
169
170         SSCR0_P(dev->port) = ssp->cr0;
171 }
172
173 /**
174  * ssp_init - setup the SSP port
175  *
176  * initialise and claim resources for the SSP port.
177  *
178  * Returns:
179  *   %-ENODEV   if the SSP port is unavailable
180  *   %-EBUSY    if the resources are already in use
181  *   %0         on success
182  */
183 int ssp_init(struct ssp_dev *dev, u32 port, u32 mode, u32 flags, u32 psp_flags,
184                                                 u32 speed)
185 {
186         int ret, irq;
187
188         if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
189                 return -EBUSY;
190         }
191
192         switch (port) {
193                 case 1:
194                         irq = IRQ_SSP;
195                         break;
196 #if defined (CONFIG_PXA27x)
197                 case 2:
198                         irq = IRQ_SSP2;
199                         break;
200                 case 3:
201                         irq = IRQ_SSP3;
202                         break;
203 #else
204                 case 2:
205                         irq = IRQ_NSSP;
206                         break;
207                 case 3:
208                         irq = IRQ_ASSP;
209                         break;
210 #endif
211                 default:
212                         return -ENODEV;
213         }
214
215         dev->port = port;
216         dev->mode = mode;
217         dev->flags = flags;
218         dev->psp_flags = psp_flags;
219         dev->speed = speed;
220
221         /* set up port type, speed, port settings */
222         SSCR0_P(dev->port) = (dev->speed | dev->mode);
223         SSCR1_P(dev->port) = dev->flags;
224         SSPSP_P(dev->port) = dev->psp_flags;
225
226         ret = request_irq(irq, ssp_interrupt, 0, "SSP", dev);
227         if (ret)
228                 goto out_region;
229
230         /* turn on SSP port clock */
231         switch (dev->port) {
232 #if defined (CONFIG_PXA27x)
233                 case 1:
234                         pxa_set_cken(CKEN23_SSP1, 1);
235                         break;
236                 case 2:
237                         pxa_set_cken(CKEN3_SSP2, 1);
238                         break;
239                 case 3:
240                         pxa_set_cken(CKEN4_SSP3, 1);
241                         break;
242 #else
243                 case 1:
244                         pxa_set_cken(CKEN3_SSP, 1);
245                         break;
246                 case 2:
247                         pxa_set_cken(CKEN9_NSSP, 1);
248                         break;
249                 case 3:
250                         pxa_set_cken(CKEN10_ASSP, 1);
251                         break;
252 #endif
253         }
254
255         return 0;
256
257 out_region:
258         release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
259         return ret;
260 }
261
262 /**
263  * ssp_exit - undo the effects of ssp_init
264  *
265  * release and free resources for the SSP port.
266  */
267 void ssp_exit(struct ssp_dev *dev)
268 {
269         int irq;
270
271         SSCR0_P(dev->port) &= ~SSCR0_SSE;
272
273         /* find irq, save power and turn off SSP port clock */
274         switch (dev->port) {
275 #if defined (CONFIG_PXA27x)
276                 case 1:
277                         irq = IRQ_SSP;
278                         pxa_set_cken(CKEN23_SSP1, 0);
279                         break;
280                 case 2:
281                         irq = IRQ_SSP2;
282                         pxa_set_cken(CKEN3_SSP2, 0);
283                         break;
284                 case 3:
285                         irq = IRQ_SSP3;
286                         pxa_set_cken(CKEN4_SSP3, 0);
287                         break;
288 #else
289                 case 1:
290                         irq = IRQ_SSP;
291                         pxa_set_cken(CKEN3_SSP, 0);
292                         break;
293                 case 2:
294                         irq = IRQ_NSSP;
295                         pxa_set_cken(CKEN9_NSSP, 0);
296                         break;
297                 case 3:
298                         irq = IRQ_ASSP;
299                         pxa_set_cken(CKEN10_ASSP, 0);
300                         break;
301 #endif
302                 default:
303                         printk(KERN_WARNING "SSP: tried to close invalid port\n");
304                         return;
305         }
306
307         free_irq(irq, dev);
308         release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
309 }
310
311 EXPORT_SYMBOL(ssp_write_word);
312 EXPORT_SYMBOL(ssp_read_word);
313 EXPORT_SYMBOL(ssp_flush);
314 EXPORT_SYMBOL(ssp_enable);
315 EXPORT_SYMBOL(ssp_disable);
316 EXPORT_SYMBOL(ssp_save_state);
317 EXPORT_SYMBOL(ssp_restore_state);
318 EXPORT_SYMBOL(ssp_init);
319 EXPORT_SYMBOL(ssp_exit);