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