1 /*
2 * linux/arch/arm/mach-sa1100/ssp.c
3 *
4 * Copyright (C) 2003 Russell King.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Generic SSP driver. This provides the generic core for simple
11 * IO-based SSP applications.
12 */
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/errno.h>
17 #include <linux/interrupt.h>
18 #include <linux/ioport.h>
19 #include <linux/init.h>
20
21 #include <asm/io.h>
22 #include <asm/irq.h>
23 #include <asm/hardware.h>
24 #include <asm/hardware/ssp.h>
25
ssp_interrupt(int irq,void * dev_id,struct pt_regs * regs)26 static void ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
27 {
28 unsigned int status = Ser4SSSR;
29
30 if (status & SSSR_ROR) {
31 printk(KERN_WARNING "SSP: receiver overrun\n");
32 }
33
34 Ser4SSSR = SSSR_ROR;
35 }
36
37 /**
38 * ssp_write_word - write a word to the SSP port
39 * @data: 16-bit, MSB justified data to write.
40 *
41 * Wait for a free entry in the SSP transmit FIFO, and write a data
42 * word to the SSP port.
43 *
44 * The caller is expected to perform the necessary locking.
45 *
46 * Returns:
47 * %-ETIMEDOUT timeout occurred (for future)
48 * 0 success
49 */
ssp_write_word(u16 data)50 int ssp_write_word(u16 data)
51 {
52 while (!(Ser4SSSR & SSSR_TNF))
53 cpu_relax();
54
55 Ser4SSDR = data;
56
57 return 0;
58 }
59
60 /**
61 * ssp_read_word - read a word from the SSP port
62 *
63 * Wait for a data word in the SSP receive FIFO, and return the
64 * received data. Data is LSB justified.
65 *
66 * Note: Currently, if data is not expected to be received, this
67 * function will wait for ever.
68 *
69 * The caller is expected to perform the necessary locking.
70 *
71 * Returns:
72 * %-ETIMEDOUT timeout occurred (for future)
73 * 16-bit data success
74 */
ssp_read_word(void)75 int ssp_read_word(void)
76 {
77 while (!(Ser4SSSR & SSSR_RNE))
78 cpu_relax();
79
80 return Ser4SSDR;
81 }
82
83 /**
84 * ssp_flush - flush the transmit and receive FIFOs
85 *
86 * Wait for the SSP to idle, and ensure that the receive FIFO
87 * is empty.
88 *
89 * The caller is expected to perform the necessary locking.
90 */
ssp_flush(void)91 void ssp_flush(void)
92 {
93 do {
94 while (Ser4SSSR & SSSR_RNE) {
95 (void) Ser4SSDR;
96 }
97 } while (Ser4SSSR & SSSR_BSY);
98 }
99
100 /**
101 * ssp_enable - enable the SSP port
102 *
103 * Turn on the SSP port.
104 */
ssp_enable(void)105 void ssp_enable(void)
106 {
107 Ser4SSCR0 |= SSCR0_SSE;
108 }
109
110 /**
111 * ssp_disable - shut down the SSP port
112 *
113 * Turn off the SSP port, optionally powering it down.
114 */
ssp_disable(void)115 void ssp_disable(void)
116 {
117 Ser4SSCR0 &= ~SSCR0_SSE;
118 }
119
120 /**
121 * ssp_save_state - save the SSP configuration
122 * @ssp: pointer to structure to save SSP configuration
123 *
124 * Save the configured SSP state for suspend.
125 */
ssp_save_state(struct ssp_state * ssp)126 void ssp_save_state(struct ssp_state *ssp)
127 {
128 ssp->cr0 = Ser4SSCR0;
129 ssp->cr1 = Ser4SSCR1;
130
131 Ser4SSCR0 &= ~SSCR0_SSE;
132 }
133
134 /**
135 * ssp_restore_state - restore a previously saved SSP configuration
136 * @ssp: pointer to configuration saved by ssp_save_state
137 *
138 * Restore the SSP configuration saved previously by ssp_save_state.
139 */
ssp_restore_state(struct ssp_state * ssp)140 void ssp_restore_state(struct ssp_state *ssp)
141 {
142 Ser4SSSR = SSSR_ROR;
143
144 Ser4SSCR0 = ssp->cr0 & ~SSCR0_SSE;
145 Ser4SSCR1 = ssp->cr1;
146 Ser4SSCR0 = ssp->cr0;
147 }
148
149 /**
150 * ssp_init - setup the SSP port
151 *
152 * initialise and claim resources for the SSP port.
153 *
154 * Returns:
155 * %-ENODEV if the SSP port is unavailable
156 * %-EBUSY if the resources are already in use
157 * %0 on success
158 */
ssp_init(void)159 int ssp_init(void)
160 {
161 int ret;
162
163 if (!(PPAR & PPAR_SPR) && (Ser4MCCR0 & MCCR0_MCE))
164 return -ENODEV;
165
166 if (!request_mem_region(__PREG(Ser4SSCR0), 0x18, "SSP")) {
167 return -EBUSY;
168 }
169
170 Ser4SSSR = SSSR_ROR;
171
172 ret = request_irq(IRQ_Ser4SSP, ssp_interrupt, 0, "SSP", NULL);
173 if (ret)
174 goto out_region;
175
176 return 0;
177
178 out_region:
179 release_mem_region(__PREG(Ser4SSCR0), 0x18);
180 return ret;
181 }
182
183 /**
184 * ssp_exit - undo the effects of ssp_init
185 *
186 * release and free resources for the SSP port.
187 */
ssp_exit(void)188 void ssp_exit(void)
189 {
190 Ser4SSCR0 &= ~SSCR0_SSE;
191
192 free_irq(IRQ_Ser4SSP, NULL);
193 release_mem_region(__PREG(Ser4SSCR0), 0x18);
194 }
195
196 MODULE_AUTHOR("Russell King");
197 MODULE_DESCRIPTION("SA11x0 SSP PIO driver");
198 MODULE_LICENSE("GPL");
199
200 EXPORT_SYMBOL(ssp_write_word);
201 EXPORT_SYMBOL(ssp_read_word);
202 EXPORT_SYMBOL(ssp_flush);
203 EXPORT_SYMBOL(ssp_enable);
204 EXPORT_SYMBOL(ssp_disable);
205 EXPORT_SYMBOL(ssp_save_state);
206 EXPORT_SYMBOL(ssp_restore_state);
207 EXPORT_SYMBOL(ssp_init);
208 EXPORT_SYMBOL(ssp_exit);
209