diff options
author | Mikael Starvik <mikael.starvik@axis.com> | 2005-07-27 14:44:44 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-27 19:26:01 -0400 |
commit | 51533b615e605d86154ec1b4e585c8ca1b0b15b7 (patch) | |
tree | 4a6d7d8494d2017632d83624fb71b36031e0e7e5 /arch/cris/arch-v32/drivers/sync_serial.c | |
parent | 5d01e6ce785884a5db5792cd2e5bb36fa82fe23c (diff) |
[PATCH] CRIS update: new subarchitecture v32
New CRIS sub architecture named v32.
From: Dave Jones <davej@redhat.com>
Fix swapped kmalloc args
Signed-off-by: Mikael Starvik <starvik@axis.com>
Signed-off-by: Dave Jones <davej@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/cris/arch-v32/drivers/sync_serial.c')
-rw-r--r-- | arch/cris/arch-v32/drivers/sync_serial.c | 1283 |
1 files changed, 1283 insertions, 0 deletions
diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c new file mode 100644 index 000000000000..c85a6df8558f --- /dev/null +++ b/arch/cris/arch-v32/drivers/sync_serial.c | |||
@@ -0,0 +1,1283 @@ | |||
1 | /* | ||
2 | * Simple synchronous serial port driver for ETRAX FS. | ||
3 | * | ||
4 | * Copyright (c) 2005 Axis Communications AB | ||
5 | * | ||
6 | * Author: Mikael Starvik | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/config.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/major.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/poll.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/timer.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | |||
24 | #include <asm/io.h> | ||
25 | #include <asm/arch/dma.h> | ||
26 | #include <asm/arch/pinmux.h> | ||
27 | #include <asm/arch/hwregs/reg_rdwr.h> | ||
28 | #include <asm/arch/hwregs/sser_defs.h> | ||
29 | #include <asm/arch/hwregs/dma_defs.h> | ||
30 | #include <asm/arch/hwregs/dma.h> | ||
31 | #include <asm/arch/hwregs/intr_vect_defs.h> | ||
32 | #include <asm/arch/hwregs/intr_vect.h> | ||
33 | #include <asm/arch/hwregs/reg_map.h> | ||
34 | #include <asm/sync_serial.h> | ||
35 | |||
36 | /* The receiver is a bit tricky beacuse of the continuous stream of data.*/ | ||
37 | /* */ | ||
38 | /* Three DMA descriptors are linked together. Each DMA descriptor is */ | ||
39 | /* responsible for port->bufchunk of a common buffer. */ | ||
40 | /* */ | ||
41 | /* +---------------------------------------------+ */ | ||
42 | /* | +----------+ +----------+ +----------+ | */ | ||
43 | /* +-> | Descr[0] |-->| Descr[1] |-->| Descr[2] |-+ */ | ||
44 | /* +----------+ +----------+ +----------+ */ | ||
45 | /* | | | */ | ||
46 | /* v v v */ | ||
47 | /* +-------------------------------------+ */ | ||
48 | /* | BUFFER | */ | ||
49 | /* +-------------------------------------+ */ | ||
50 | /* |<- data_avail ->| */ | ||
51 | /* readp writep */ | ||
52 | /* */ | ||
53 | /* If the application keeps up the pace readp will be right after writep.*/ | ||
54 | /* If the application can't keep the pace we have to throw away data. */ | ||
55 | /* The idea is that readp should be ready with the data pointed out by */ | ||
56 | /* Descr[i] when the DMA has filled in Descr[i+1]. */ | ||
57 | /* Otherwise we will discard */ | ||
58 | /* the rest of the data pointed out by Descr1 and set readp to the start */ | ||
59 | /* of Descr2 */ | ||
60 | |||
61 | #define SYNC_SERIAL_MAJOR 125 | ||
62 | |||
63 | /* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */ | ||
64 | /* words can be handled */ | ||
65 | #define IN_BUFFER_SIZE 12288 | ||
66 | #define IN_DESCR_SIZE 256 | ||
67 | #define NUM_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE) | ||
68 | #define OUT_BUFFER_SIZE 4096 | ||
69 | |||
70 | #define DEFAULT_FRAME_RATE 0 | ||
71 | #define DEFAULT_WORD_RATE 7 | ||
72 | |||
73 | /* NOTE: Enabling some debug will likely cause overrun or underrun, | ||
74 | * especially if manual mode is use. | ||
75 | */ | ||
76 | #define DEBUG(x) | ||
77 | #define DEBUGREAD(x) | ||
78 | #define DEBUGWRITE(x) | ||
79 | #define DEBUGPOLL(x) | ||
80 | #define DEBUGRXINT(x) | ||
81 | #define DEBUGTXINT(x) | ||
82 | |||
83 | typedef struct sync_port | ||
84 | { | ||
85 | reg_scope_instances regi_sser; | ||
86 | reg_scope_instances regi_dmain; | ||
87 | reg_scope_instances regi_dmaout; | ||
88 | |||
89 | char started; /* 1 if port has been started */ | ||
90 | char port_nbr; /* Port 0 or 1 */ | ||
91 | char busy; /* 1 if port is busy */ | ||
92 | |||
93 | char enabled; /* 1 if port is enabled */ | ||
94 | char use_dma; /* 1 if port uses dma */ | ||
95 | char tr_running; | ||
96 | |||
97 | char init_irqs; | ||
98 | int output; | ||
99 | int input; | ||
100 | |||
101 | volatile unsigned int out_count; /* Remaining bytes for current transfer */ | ||
102 | unsigned char* outp; /* Current position in out_buffer */ | ||
103 | volatile unsigned char* volatile readp; /* Next byte to be read by application */ | ||
104 | volatile unsigned char* volatile writep; /* Next byte to be written by etrax */ | ||
105 | unsigned int in_buffer_size; | ||
106 | unsigned int inbufchunk; | ||
107 | unsigned char out_buffer[OUT_BUFFER_SIZE] __attribute__ ((aligned(32))); | ||
108 | unsigned char in_buffer[IN_BUFFER_SIZE]__attribute__ ((aligned(32))); | ||
109 | unsigned char flip[IN_BUFFER_SIZE] __attribute__ ((aligned(32))); | ||
110 | struct dma_descr_data* next_rx_desc; | ||
111 | struct dma_descr_data* prev_rx_desc; | ||
112 | int full; | ||
113 | |||
114 | dma_descr_data in_descr[NUM_IN_DESCR] __attribute__ ((__aligned__(16))); | ||
115 | dma_descr_context in_context __attribute__ ((__aligned__(32))); | ||
116 | dma_descr_data out_descr __attribute__ ((__aligned__(16))); | ||
117 | dma_descr_context out_context __attribute__ ((__aligned__(32))); | ||
118 | wait_queue_head_t out_wait_q; | ||
119 | wait_queue_head_t in_wait_q; | ||
120 | |||
121 | spinlock_t lock; | ||
122 | } sync_port; | ||
123 | |||
124 | static int etrax_sync_serial_init(void); | ||
125 | static void initialize_port(int portnbr); | ||
126 | static inline int sync_data_avail(struct sync_port *port); | ||
127 | |||
128 | static int sync_serial_open(struct inode *, struct file*); | ||
129 | static int sync_serial_release(struct inode*, struct file*); | ||
130 | static unsigned int sync_serial_poll(struct file *filp, poll_table *wait); | ||
131 | |||
132 | static int sync_serial_ioctl(struct inode*, struct file*, | ||
133 | unsigned int cmd, unsigned long arg); | ||
134 | static ssize_t sync_serial_write(struct file * file, const char * buf, | ||
135 | size_t count, loff_t *ppos); | ||
136 | static ssize_t sync_serial_read(struct file *file, char *buf, | ||
137 | size_t count, loff_t *ppos); | ||
138 | |||
139 | #if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \ | ||
140 | defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \ | ||
141 | (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \ | ||
142 | defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)) | ||
143 | #define SYNC_SER_DMA | ||
144 | #endif | ||
145 | |||
146 | static void send_word(sync_port* port); | ||
147 | static void start_dma(struct sync_port *port, const char* data, int count); | ||
148 | static void start_dma_in(sync_port* port); | ||
149 | #ifdef SYNC_SER_DMA | ||
150 | static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs); | ||
151 | static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs); | ||
152 | #endif | ||
153 | |||
154 | #if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \ | ||
155 | !defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \ | ||
156 | (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \ | ||
157 | !defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)) | ||
158 | #define SYNC_SER_MANUAL | ||
159 | #endif | ||
160 | #ifdef SYNC_SER_MANUAL | ||
161 | static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * regs); | ||
162 | #endif | ||
163 | |||
164 | /* The ports */ | ||
165 | static struct sync_port ports[]= | ||
166 | { | ||
167 | { | ||
168 | .regi_sser = regi_sser0, | ||
169 | .regi_dmaout = regi_dma4, | ||
170 | .regi_dmain = regi_dma5, | ||
171 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) | ||
172 | .use_dma = 1, | ||
173 | #else | ||
174 | .use_dma = 0, | ||
175 | #endif | ||
176 | }, | ||
177 | { | ||
178 | .regi_sser = regi_sser1, | ||
179 | .regi_dmaout = regi_dma6, | ||
180 | .regi_dmain = regi_dma7, | ||
181 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) | ||
182 | .use_dma = 1, | ||
183 | #else | ||
184 | .use_dma = 0, | ||
185 | #endif | ||
186 | } | ||
187 | }; | ||
188 | |||
189 | #define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port)) | ||
190 | |||
191 | static struct file_operations sync_serial_fops = { | ||
192 | .owner = THIS_MODULE, | ||
193 | .write = sync_serial_write, | ||
194 | .read = sync_serial_read, | ||
195 | .poll = sync_serial_poll, | ||
196 | .ioctl = sync_serial_ioctl, | ||
197 | .open = sync_serial_open, | ||
198 | .release = sync_serial_release | ||
199 | }; | ||
200 | |||
201 | static int __init etrax_sync_serial_init(void) | ||
202 | { | ||
203 | ports[0].enabled = 0; | ||
204 | ports[1].enabled = 0; | ||
205 | |||
206 | if (register_chrdev(SYNC_SERIAL_MAJOR,"sync serial", &sync_serial_fops) <0 ) | ||
207 | { | ||
208 | printk("unable to get major for synchronous serial port\n"); | ||
209 | return -EBUSY; | ||
210 | } | ||
211 | |||
212 | /* Initialize Ports */ | ||
213 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) | ||
214 | if (crisv32_pinmux_alloc_fixed(pinmux_sser0)) | ||
215 | { | ||
216 | printk("Unable to allocate pins for syncrhronous serial port 0\n"); | ||
217 | return -EIO; | ||
218 | } | ||
219 | ports[0].enabled = 1; | ||
220 | initialize_port(0); | ||
221 | #endif | ||
222 | |||
223 | #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) | ||
224 | if (crisv32_pinmux_alloc_fixed(pinmux_sser1)) | ||
225 | { | ||
226 | printk("Unable to allocate pins for syncrhronous serial port 0\n"); | ||
227 | return -EIO; | ||
228 | } | ||
229 | ports[1].enabled = 1; | ||
230 | initialize_port(1); | ||
231 | #endif | ||
232 | |||
233 | printk("ETRAX FS synchronous serial port driver\n"); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static void __init initialize_port(int portnbr) | ||
238 | { | ||
239 | struct sync_port* port = &ports[portnbr]; | ||
240 | reg_sser_rw_cfg cfg = {0}; | ||
241 | reg_sser_rw_frm_cfg frm_cfg = {0}; | ||
242 | reg_sser_rw_tr_cfg tr_cfg = {0}; | ||
243 | reg_sser_rw_rec_cfg rec_cfg = {0}; | ||
244 | |||
245 | DEBUG(printk("Init sync serial port %d\n", portnbr)); | ||
246 | |||
247 | port->port_nbr = portnbr; | ||
248 | port->init_irqs = 1; | ||
249 | |||
250 | port->outp = port->out_buffer; | ||
251 | port->output = 1; | ||
252 | port->input = 0; | ||
253 | |||
254 | port->readp = port->flip; | ||
255 | port->writep = port->flip; | ||
256 | port->in_buffer_size = IN_BUFFER_SIZE; | ||
257 | port->inbufchunk = IN_DESCR_SIZE; | ||
258 | port->next_rx_desc = &port->in_descr[0]; | ||
259 | port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR-1]; | ||
260 | port->prev_rx_desc->eol = 1; | ||
261 | |||
262 | init_waitqueue_head(&port->out_wait_q); | ||
263 | init_waitqueue_head(&port->in_wait_q); | ||
264 | |||
265 | spin_lock_init(&port->lock); | ||
266 | |||
267 | cfg.out_clk_src = regk_sser_intern_clk; | ||
268 | cfg.out_clk_pol = regk_sser_pos; | ||
269 | cfg.clk_od_mode = regk_sser_no; | ||
270 | cfg.clk_dir = regk_sser_out; | ||
271 | cfg.gate_clk = regk_sser_no; | ||
272 | cfg.base_freq = regk_sser_f29_493; | ||
273 | cfg.clk_div = 256; | ||
274 | REG_WR(sser, port->regi_sser, rw_cfg, cfg); | ||
275 | |||
276 | frm_cfg.wordrate = DEFAULT_WORD_RATE; | ||
277 | frm_cfg.type = regk_sser_edge; | ||
278 | frm_cfg.frame_pin_dir = regk_sser_out; | ||
279 | frm_cfg.frame_pin_use = regk_sser_frm; | ||
280 | frm_cfg.status_pin_dir = regk_sser_in; | ||
281 | frm_cfg.status_pin_use = regk_sser_hold; | ||
282 | frm_cfg.out_on = regk_sser_tr; | ||
283 | frm_cfg.tr_delay = 1; | ||
284 | REG_WR(sser, port->regi_sser, rw_frm_cfg, frm_cfg); | ||
285 | |||
286 | tr_cfg.urun_stop = regk_sser_no; | ||
287 | tr_cfg.sample_size = 7; | ||
288 | tr_cfg.sh_dir = regk_sser_msbfirst; | ||
289 | tr_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no; | ||
290 | tr_cfg.rate_ctrl = regk_sser_bulk; | ||
291 | tr_cfg.data_pin_use = regk_sser_dout; | ||
292 | tr_cfg.bulk_wspace = 1; | ||
293 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); | ||
294 | |||
295 | rec_cfg.sample_size = 7; | ||
296 | rec_cfg.sh_dir = regk_sser_msbfirst; | ||
297 | rec_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no; | ||
298 | rec_cfg.fifo_thr = regk_sser_inf; | ||
299 | REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); | ||
300 | } | ||
301 | |||
302 | static inline int sync_data_avail(struct sync_port *port) | ||
303 | { | ||
304 | int avail; | ||
305 | unsigned char *start; | ||
306 | unsigned char *end; | ||
307 | |||
308 | start = (unsigned char*)port->readp; /* cast away volatile */ | ||
309 | end = (unsigned char*)port->writep; /* cast away volatile */ | ||
310 | /* 0123456789 0123456789 | ||
311 | * ----- - ----- | ||
312 | * ^rp ^wp ^wp ^rp | ||
313 | */ | ||
314 | |||
315 | if (end >= start) | ||
316 | avail = end - start; | ||
317 | else | ||
318 | avail = port->in_buffer_size - (start - end); | ||
319 | return avail; | ||
320 | } | ||
321 | |||
322 | static inline int sync_data_avail_to_end(struct sync_port *port) | ||
323 | { | ||
324 | int avail; | ||
325 | unsigned char *start; | ||
326 | unsigned char *end; | ||
327 | |||
328 | start = (unsigned char*)port->readp; /* cast away volatile */ | ||
329 | end = (unsigned char*)port->writep; /* cast away volatile */ | ||
330 | /* 0123456789 0123456789 | ||
331 | * ----- ----- | ||
332 | * ^rp ^wp ^wp ^rp | ||
333 | */ | ||
334 | |||
335 | if (end >= start) | ||
336 | avail = end - start; | ||
337 | else | ||
338 | avail = port->flip + port->in_buffer_size - start; | ||
339 | return avail; | ||
340 | } | ||
341 | |||
342 | static int sync_serial_open(struct inode *inode, struct file *file) | ||
343 | { | ||
344 | int dev = MINOR(inode->i_rdev); | ||
345 | sync_port* port; | ||
346 | reg_dma_rw_cfg cfg = {.en = regk_dma_yes}; | ||
347 | reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes}; | ||
348 | |||
349 | DEBUG(printk("Open sync serial port %d\n", dev)); | ||
350 | |||
351 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | ||
352 | { | ||
353 | DEBUG(printk("Invalid minor %d\n", dev)); | ||
354 | return -ENODEV; | ||
355 | } | ||
356 | port = &ports[dev]; | ||
357 | /* Allow open this device twice (assuming one reader and one writer) */ | ||
358 | if (port->busy == 2) | ||
359 | { | ||
360 | DEBUG(printk("Device is busy.. \n")); | ||
361 | return -EBUSY; | ||
362 | } | ||
363 | if (port->init_irqs) { | ||
364 | if (port->use_dma) { | ||
365 | if (port == &ports[0]){ | ||
366 | #ifdef SYNC_SER_DMA | ||
367 | if(request_irq(DMA4_INTR_VECT, | ||
368 | tr_interrupt, | ||
369 | 0, | ||
370 | "synchronous serial 0 dma tr", | ||
371 | &ports[0])) { | ||
372 | printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); | ||
373 | return -EBUSY; | ||
374 | } else if(request_irq(DMA5_INTR_VECT, | ||
375 | rx_interrupt, | ||
376 | 0, | ||
377 | "synchronous serial 1 dma rx", | ||
378 | &ports[0])) { | ||
379 | free_irq(DMA4_INTR_VECT, &port[0]); | ||
380 | printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); | ||
381 | return -EBUSY; | ||
382 | } else if (crisv32_request_dma(SYNC_SER0_TX_DMA_NBR, | ||
383 | "synchronous serial 0 dma tr", | ||
384 | DMA_VERBOSE_ON_ERROR, | ||
385 | 0, | ||
386 | dma_sser0)) { | ||
387 | free_irq(DMA4_INTR_VECT, &port[0]); | ||
388 | free_irq(DMA5_INTR_VECT, &port[0]); | ||
389 | printk(KERN_CRIT "Can't allocate sync serial port 0 TX DMA channel"); | ||
390 | return -EBUSY; | ||
391 | } else if (crisv32_request_dma(SYNC_SER0_RX_DMA_NBR, | ||
392 | "synchronous serial 0 dma rec", | ||
393 | DMA_VERBOSE_ON_ERROR, | ||
394 | 0, | ||
395 | dma_sser0)) { | ||
396 | crisv32_free_dma(SYNC_SER0_TX_DMA_NBR); | ||
397 | free_irq(DMA4_INTR_VECT, &port[0]); | ||
398 | free_irq(DMA5_INTR_VECT, &port[0]); | ||
399 | printk(KERN_CRIT "Can't allocate sync serial port 1 RX DMA channel"); | ||
400 | return -EBUSY; | ||
401 | } | ||
402 | #endif | ||
403 | } | ||
404 | else if (port == &ports[1]){ | ||
405 | #ifdef SYNC_SER_DMA | ||
406 | if (request_irq(DMA6_INTR_VECT, | ||
407 | tr_interrupt, | ||
408 | 0, | ||
409 | "synchronous serial 1 dma tr", | ||
410 | &ports[1])) { | ||
411 | printk(KERN_CRIT "Can't allocate sync serial port 1 IRQ"); | ||
412 | return -EBUSY; | ||
413 | } else if (request_irq(DMA7_INTR_VECT, | ||
414 | rx_interrupt, | ||
415 | 0, | ||
416 | "synchronous serial 1 dma rx", | ||
417 | &ports[1])) { | ||
418 | free_irq(DMA6_INTR_VECT, &ports[1]); | ||
419 | printk(KERN_CRIT "Can't allocate sync serial port 3 IRQ"); | ||
420 | return -EBUSY; | ||
421 | } else if (crisv32_request_dma(SYNC_SER1_TX_DMA_NBR, | ||
422 | "synchronous serial 1 dma tr", | ||
423 | DMA_VERBOSE_ON_ERROR, | ||
424 | 0, | ||
425 | dma_sser1)) { | ||
426 | free_irq(21, &ports[1]); | ||
427 | free_irq(20, &ports[1]); | ||
428 | printk(KERN_CRIT "Can't allocate sync serial port 3 TX DMA channel"); | ||
429 | return -EBUSY; | ||
430 | } else if (crisv32_request_dma(SYNC_SER1_RX_DMA_NBR, | ||
431 | "synchronous serial 3 dma rec", | ||
432 | DMA_VERBOSE_ON_ERROR, | ||
433 | 0, | ||
434 | dma_sser1)) { | ||
435 | crisv32_free_dma(SYNC_SER1_TX_DMA_NBR); | ||
436 | free_irq(DMA6_INTR_VECT, &ports[1]); | ||
437 | free_irq(DMA7_INTR_VECT, &ports[1]); | ||
438 | printk(KERN_CRIT "Can't allocate sync serial port 3 RX DMA channel"); | ||
439 | return -EBUSY; | ||
440 | } | ||
441 | #endif | ||
442 | } | ||
443 | |||
444 | /* Enable DMAs */ | ||
445 | REG_WR(dma, port->regi_dmain, rw_cfg, cfg); | ||
446 | REG_WR(dma, port->regi_dmaout, rw_cfg, cfg); | ||
447 | /* Enable DMA IRQs */ | ||
448 | REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask); | ||
449 | REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask); | ||
450 | /* Set up wordsize = 2 for DMAs. */ | ||
451 | DMA_WR_CMD (port->regi_dmain, regk_dma_set_w_size1); | ||
452 | DMA_WR_CMD (port->regi_dmaout, regk_dma_set_w_size1); | ||
453 | |||
454 | start_dma_in(port); | ||
455 | port->init_irqs = 0; | ||
456 | } else { /* !port->use_dma */ | ||
457 | #ifdef SYNC_SER_MANUAL | ||
458 | if (port == &ports[0]) { | ||
459 | if (request_irq(SSER0_INTR_VECT, | ||
460 | manual_interrupt, | ||
461 | 0, | ||
462 | "synchronous serial manual irq", | ||
463 | &ports[0])) { | ||
464 | printk("Can't allocate sync serial manual irq"); | ||
465 | return -EBUSY; | ||
466 | } | ||
467 | } else if (port == &ports[1]) { | ||
468 | if (request_irq(SSER1_INTR_VECT, | ||
469 | manual_interrupt, | ||
470 | 0, | ||
471 | "synchronous serial manual irq", | ||
472 | &ports[1])) { | ||
473 | printk(KERN_CRIT "Can't allocate sync serial manual irq"); | ||
474 | return -EBUSY; | ||
475 | } | ||
476 | } | ||
477 | port->init_irqs = 0; | ||
478 | #else | ||
479 | panic("sync_serial: Manual mode not supported.\n"); | ||
480 | #endif /* SYNC_SER_MANUAL */ | ||
481 | } | ||
482 | } /* port->init_irqs */ | ||
483 | |||
484 | port->busy++; | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int sync_serial_release(struct inode *inode, struct file *file) | ||
489 | { | ||
490 | int dev = MINOR(inode->i_rdev); | ||
491 | sync_port* port; | ||
492 | |||
493 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | ||
494 | { | ||
495 | DEBUG(printk("Invalid minor %d\n", dev)); | ||
496 | return -ENODEV; | ||
497 | } | ||
498 | port = &ports[dev]; | ||
499 | if (port->busy) | ||
500 | port->busy--; | ||
501 | if (!port->busy) | ||
502 | /* XXX */ ; | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static unsigned int sync_serial_poll(struct file *file, poll_table *wait) | ||
507 | { | ||
508 | int dev = MINOR(file->f_dentry->d_inode->i_rdev); | ||
509 | unsigned int mask = 0; | ||
510 | sync_port* port; | ||
511 | DEBUGPOLL( static unsigned int prev_mask = 0; ); | ||
512 | |||
513 | port = &ports[dev]; | ||
514 | poll_wait(file, &port->out_wait_q, wait); | ||
515 | poll_wait(file, &port->in_wait_q, wait); | ||
516 | /* Some room to write */ | ||
517 | if (port->out_count < OUT_BUFFER_SIZE) | ||
518 | mask |= POLLOUT | POLLWRNORM; | ||
519 | /* At least an inbufchunk of data */ | ||
520 | if (sync_data_avail(port) >= port->inbufchunk) | ||
521 | mask |= POLLIN | POLLRDNORM; | ||
522 | |||
523 | DEBUGPOLL(if (mask != prev_mask) | ||
524 | printk("sync_serial_poll: mask 0x%08X %s %s\n", mask, | ||
525 | mask&POLLOUT?"POLLOUT":"", mask&POLLIN?"POLLIN":""); | ||
526 | prev_mask = mask; | ||
527 | ); | ||
528 | return mask; | ||
529 | } | ||
530 | |||
531 | static int sync_serial_ioctl(struct inode *inode, struct file *file, | ||
532 | unsigned int cmd, unsigned long arg) | ||
533 | { | ||
534 | int return_val = 0; | ||
535 | int dev = MINOR(file->f_dentry->d_inode->i_rdev); | ||
536 | sync_port* port; | ||
537 | reg_sser_rw_tr_cfg tr_cfg; | ||
538 | reg_sser_rw_rec_cfg rec_cfg; | ||
539 | reg_sser_rw_frm_cfg frm_cfg; | ||
540 | reg_sser_rw_cfg gen_cfg; | ||
541 | reg_sser_rw_intr_mask intr_mask; | ||
542 | |||
543 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | ||
544 | { | ||
545 | DEBUG(printk("Invalid minor %d\n", dev)); | ||
546 | return -1; | ||
547 | } | ||
548 | port = &ports[dev]; | ||
549 | spin_lock_irq(&port->lock); | ||
550 | |||
551 | tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); | ||
552 | rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); | ||
553 | frm_cfg = REG_RD(sser, port->regi_sser, rw_frm_cfg); | ||
554 | gen_cfg = REG_RD(sser, port->regi_sser, rw_cfg); | ||
555 | intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); | ||
556 | |||
557 | switch(cmd) | ||
558 | { | ||
559 | case SSP_SPEED: | ||
560 | if (GET_SPEED(arg) == CODEC) | ||
561 | { | ||
562 | gen_cfg.base_freq = regk_sser_f32; | ||
563 | /* FREQ = 0 => 4 MHz => clk_div = 7*/ | ||
564 | gen_cfg.clk_div = 6 + (1 << GET_FREQ(arg)); | ||
565 | } | ||
566 | else | ||
567 | { | ||
568 | gen_cfg.base_freq = regk_sser_f29_493; | ||
569 | switch (GET_SPEED(arg)) | ||
570 | { | ||
571 | case SSP150: | ||
572 | gen_cfg.clk_div = 29493000 / (150 * 8) - 1; | ||
573 | break; | ||
574 | case SSP300: | ||
575 | gen_cfg.clk_div = 29493000 / (300 * 8) - 1; | ||
576 | break; | ||
577 | case SSP600: | ||
578 | gen_cfg.clk_div = 29493000 / (600 * 8) - 1; | ||
579 | break; | ||
580 | case SSP1200: | ||
581 | gen_cfg.clk_div = 29493000 / (1200 * 8) - 1; | ||
582 | break; | ||
583 | case SSP2400: | ||
584 | gen_cfg.clk_div = 29493000 / (2400 * 8) - 1; | ||
585 | break; | ||
586 | case SSP4800: | ||
587 | gen_cfg.clk_div = 29493000 / (4800 * 8) - 1; | ||
588 | break; | ||
589 | case SSP9600: | ||
590 | gen_cfg.clk_div = 29493000 / (9600 * 8) - 1; | ||
591 | break; | ||
592 | case SSP19200: | ||
593 | gen_cfg.clk_div = 29493000 / (19200 * 8) - 1; | ||
594 | break; | ||
595 | case SSP28800: | ||
596 | gen_cfg.clk_div = 29493000 / (28800 * 8) - 1; | ||
597 | break; | ||
598 | case SSP57600: | ||
599 | gen_cfg.clk_div = 29493000 / (57600 * 8) - 1; | ||
600 | break; | ||
601 | case SSP115200: | ||
602 | gen_cfg.clk_div = 29493000 / (115200 * 8) - 1; | ||
603 | break; | ||
604 | case SSP230400: | ||
605 | gen_cfg.clk_div = 29493000 / (230400 * 8) - 1; | ||
606 | break; | ||
607 | case SSP460800: | ||
608 | gen_cfg.clk_div = 29493000 / (460800 * 8) - 1; | ||
609 | break; | ||
610 | case SSP921600: | ||
611 | gen_cfg.clk_div = 29493000 / (921600 * 8) - 1; | ||
612 | break; | ||
613 | case SSP3125000: | ||
614 | gen_cfg.base_freq = regk_sser_f100; | ||
615 | gen_cfg.clk_div = 100000000 / (3125000 * 8) - 1; | ||
616 | break; | ||
617 | |||
618 | } | ||
619 | } | ||
620 | frm_cfg.wordrate = GET_WORD_RATE(arg); | ||
621 | |||
622 | break; | ||
623 | case SSP_MODE: | ||
624 | switch(arg) | ||
625 | { | ||
626 | case MASTER_OUTPUT: | ||
627 | port->output = 1; | ||
628 | port->input = 0; | ||
629 | gen_cfg.clk_dir = regk_sser_out; | ||
630 | break; | ||
631 | case SLAVE_OUTPUT: | ||
632 | port->output = 1; | ||
633 | port->input = 0; | ||
634 | gen_cfg.clk_dir = regk_sser_in; | ||
635 | break; | ||
636 | case MASTER_INPUT: | ||
637 | port->output = 0; | ||
638 | port->input = 1; | ||
639 | gen_cfg.clk_dir = regk_sser_out; | ||
640 | break; | ||
641 | case SLAVE_INPUT: | ||
642 | port->output = 0; | ||
643 | port->input = 1; | ||
644 | gen_cfg.clk_dir = regk_sser_in; | ||
645 | break; | ||
646 | case MASTER_BIDIR: | ||
647 | port->output = 1; | ||
648 | port->input = 1; | ||
649 | gen_cfg.clk_dir = regk_sser_out; | ||
650 | break; | ||
651 | case SLAVE_BIDIR: | ||
652 | port->output = 1; | ||
653 | port->input = 1; | ||
654 | gen_cfg.clk_dir = regk_sser_in; | ||
655 | break; | ||
656 | default: | ||
657 | spin_unlock_irq(&port->lock); | ||
658 | return -EINVAL; | ||
659 | |||
660 | } | ||
661 | if (!port->use_dma || (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)) | ||
662 | intr_mask.rdav = regk_sser_yes; | ||
663 | break; | ||
664 | case SSP_FRAME_SYNC: | ||
665 | if (arg & NORMAL_SYNC) | ||
666 | frm_cfg.tr_delay = 1; | ||
667 | else if (arg & EARLY_SYNC) | ||
668 | frm_cfg.tr_delay = 0; | ||
669 | |||
670 | tr_cfg.bulk_wspace = frm_cfg.tr_delay; | ||
671 | frm_cfg.early_wend = regk_sser_yes; | ||
672 | if (arg & BIT_SYNC) | ||
673 | frm_cfg.type = regk_sser_edge; | ||
674 | else if (arg & WORD_SYNC) | ||
675 | frm_cfg.type = regk_sser_level; | ||
676 | else if (arg & EXTENDED_SYNC) | ||
677 | frm_cfg.early_wend = regk_sser_no; | ||
678 | |||
679 | if (arg & SYNC_ON) | ||
680 | frm_cfg.frame_pin_use = regk_sser_frm; | ||
681 | else if (arg & SYNC_OFF) | ||
682 | frm_cfg.frame_pin_use = regk_sser_gio0; | ||
683 | |||
684 | if (arg & WORD_SIZE_8) | ||
685 | rec_cfg.sample_size = tr_cfg.sample_size = 7; | ||
686 | else if (arg & WORD_SIZE_12) | ||
687 | rec_cfg.sample_size = tr_cfg.sample_size = 11; | ||
688 | else if (arg & WORD_SIZE_16) | ||
689 | rec_cfg.sample_size = tr_cfg.sample_size = 15; | ||
690 | else if (arg & WORD_SIZE_24) | ||
691 | rec_cfg.sample_size = tr_cfg.sample_size = 23; | ||
692 | else if (arg & WORD_SIZE_32) | ||
693 | rec_cfg.sample_size = tr_cfg.sample_size = 31; | ||
694 | |||
695 | if (arg & BIT_ORDER_MSB) | ||
696 | rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_msbfirst; | ||
697 | else if (arg & BIT_ORDER_LSB) | ||
698 | rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_lsbfirst; | ||
699 | |||
700 | if (arg & FLOW_CONTROL_ENABLE) | ||
701 | rec_cfg.fifo_thr = regk_sser_thr16; | ||
702 | else if (arg & FLOW_CONTROL_DISABLE) | ||
703 | rec_cfg.fifo_thr = regk_sser_inf; | ||
704 | |||
705 | if (arg & CLOCK_NOT_GATED) | ||
706 | gen_cfg.gate_clk = regk_sser_no; | ||
707 | else if (arg & CLOCK_GATED) | ||
708 | gen_cfg.gate_clk = regk_sser_yes; | ||
709 | |||
710 | break; | ||
711 | case SSP_IPOLARITY: | ||
712 | /* NOTE!! negedge is considered NORMAL */ | ||
713 | if (arg & CLOCK_NORMAL) | ||
714 | rec_cfg.clk_pol = regk_sser_neg; | ||
715 | else if (arg & CLOCK_INVERT) | ||
716 | rec_cfg.clk_pol = regk_sser_pos; | ||
717 | |||
718 | if (arg & FRAME_NORMAL) | ||
719 | frm_cfg.level = regk_sser_pos_hi; | ||
720 | else if (arg & FRAME_INVERT) | ||
721 | frm_cfg.level = regk_sser_neg_lo; | ||
722 | |||
723 | if (arg & STATUS_NORMAL) | ||
724 | gen_cfg.hold_pol = regk_sser_pos; | ||
725 | else if (arg & STATUS_INVERT) | ||
726 | gen_cfg.hold_pol = regk_sser_neg; | ||
727 | break; | ||
728 | case SSP_OPOLARITY: | ||
729 | if (arg & CLOCK_NORMAL) | ||
730 | gen_cfg.out_clk_pol = regk_sser_neg; | ||
731 | else if (arg & CLOCK_INVERT) | ||
732 | gen_cfg.out_clk_pol = regk_sser_pos; | ||
733 | |||
734 | if (arg & FRAME_NORMAL) | ||
735 | frm_cfg.level = regk_sser_pos_hi; | ||
736 | else if (arg & FRAME_INVERT) | ||
737 | frm_cfg.level = regk_sser_neg_lo; | ||
738 | |||
739 | if (arg & STATUS_NORMAL) | ||
740 | gen_cfg.hold_pol = regk_sser_pos; | ||
741 | else if (arg & STATUS_INVERT) | ||
742 | gen_cfg.hold_pol = regk_sser_neg; | ||
743 | break; | ||
744 | case SSP_SPI: | ||
745 | rec_cfg.fifo_thr = regk_sser_inf; | ||
746 | rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_msbfirst; | ||
747 | rec_cfg.sample_size = tr_cfg.sample_size = 7; | ||
748 | frm_cfg.frame_pin_use = regk_sser_frm; | ||
749 | frm_cfg.type = regk_sser_level; | ||
750 | frm_cfg.tr_delay = 1; | ||
751 | frm_cfg.level = regk_sser_neg_lo; | ||
752 | if (arg & SPI_SLAVE) | ||
753 | { | ||
754 | rec_cfg.clk_pol = regk_sser_neg; | ||
755 | gen_cfg.clk_dir = regk_sser_in; | ||
756 | port->input = 1; | ||
757 | port->output = 0; | ||
758 | } | ||
759 | else | ||
760 | { | ||
761 | gen_cfg.out_clk_pol = regk_sser_pos; | ||
762 | port->input = 0; | ||
763 | port->output = 1; | ||
764 | gen_cfg.clk_dir = regk_sser_out; | ||
765 | } | ||
766 | break; | ||
767 | case SSP_INBUFCHUNK: | ||
768 | break; | ||
769 | default: | ||
770 | return_val = -1; | ||
771 | } | ||
772 | |||
773 | |||
774 | if (port->started) | ||
775 | { | ||
776 | tr_cfg.tr_en = port->output; | ||
777 | rec_cfg.rec_en = port->input; | ||
778 | } | ||
779 | |||
780 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); | ||
781 | REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); | ||
782 | REG_WR(sser, port->regi_sser, rw_frm_cfg, frm_cfg); | ||
783 | REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); | ||
784 | REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg); | ||
785 | |||
786 | spin_unlock_irq(&port->lock); | ||
787 | return return_val; | ||
788 | } | ||
789 | |||
790 | static ssize_t sync_serial_write(struct file * file, const char * buf, | ||
791 | size_t count, loff_t *ppos) | ||
792 | { | ||
793 | int dev = MINOR(file->f_dentry->d_inode->i_rdev); | ||
794 | DECLARE_WAITQUEUE(wait, current); | ||
795 | sync_port *port; | ||
796 | unsigned long c, c1; | ||
797 | unsigned long free_outp; | ||
798 | unsigned long outp; | ||
799 | unsigned long out_buffer; | ||
800 | unsigned long flags; | ||
801 | |||
802 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | ||
803 | { | ||
804 | DEBUG(printk("Invalid minor %d\n", dev)); | ||
805 | return -ENODEV; | ||
806 | } | ||
807 | port = &ports[dev]; | ||
808 | |||
809 | DEBUGWRITE(printk("W d%d c %lu (%d/%d)\n", port->port_nbr, count, port->out_count, OUT_BUFFER_SIZE)); | ||
810 | /* Space to end of buffer */ | ||
811 | /* | ||
812 | * out_buffer <c1>012345<- c ->OUT_BUFFER_SIZE | ||
813 | * outp^ +out_count | ||
814 | ^free_outp | ||
815 | * out_buffer 45<- c ->0123OUT_BUFFER_SIZE | ||
816 | * +out_count outp^ | ||
817 | * free_outp | ||
818 | * | ||
819 | */ | ||
820 | |||
821 | /* Read variables that may be updated by interrupts */ | ||
822 | spin_lock_irqsave(&port->lock, flags); | ||
823 | count = count > OUT_BUFFER_SIZE - port->out_count ? OUT_BUFFER_SIZE - port->out_count : count; | ||
824 | outp = (unsigned long)port->outp; | ||
825 | free_outp = outp + port->out_count; | ||
826 | spin_unlock_irqrestore(&port->lock, flags); | ||
827 | out_buffer = (unsigned long)port->out_buffer; | ||
828 | |||
829 | /* Find out where and how much to write */ | ||
830 | if (free_outp >= out_buffer + OUT_BUFFER_SIZE) | ||
831 | free_outp -= OUT_BUFFER_SIZE; | ||
832 | if (free_outp >= outp) | ||
833 | c = out_buffer + OUT_BUFFER_SIZE - free_outp; | ||
834 | else | ||
835 | c = outp - free_outp; | ||
836 | if (c > count) | ||
837 | c = count; | ||
838 | |||
839 | // DEBUGWRITE(printk("w op %08lX fop %08lX c %lu\n", outp, free_outp, c)); | ||
840 | if (copy_from_user((void*)free_outp, buf, c)) | ||
841 | return -EFAULT; | ||
842 | |||
843 | if (c != count) { | ||
844 | buf += c; | ||
845 | c1 = count - c; | ||
846 | DEBUGWRITE(printk("w2 fi %lu c %lu c1 %lu\n", free_outp-out_buffer, c, c1)); | ||
847 | if (copy_from_user((void*)out_buffer, buf, c1)) | ||
848 | return -EFAULT; | ||
849 | } | ||
850 | spin_lock_irqsave(&port->lock, flags); | ||
851 | port->out_count += count; | ||
852 | spin_unlock_irqrestore(&port->lock, flags); | ||
853 | |||
854 | /* Make sure transmitter/receiver is running */ | ||
855 | if (!port->started) | ||
856 | { | ||
857 | reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); | ||
858 | reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); | ||
859 | reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); | ||
860 | cfg.en = regk_sser_yes; | ||
861 | tr_cfg.tr_en = port->output; | ||
862 | rec_cfg.rec_en = port->input; | ||
863 | REG_WR(sser, port->regi_sser, rw_cfg, cfg); | ||
864 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); | ||
865 | REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); | ||
866 | port->started = 1; | ||
867 | } | ||
868 | |||
869 | if (file->f_flags & O_NONBLOCK) { | ||
870 | spin_lock_irqsave(&port->lock, flags); | ||
871 | if (!port->tr_running) { | ||
872 | if (!port->use_dma) { | ||
873 | reg_sser_rw_intr_mask intr_mask; | ||
874 | intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); | ||
875 | /* Start sender by writing data */ | ||
876 | send_word(port); | ||
877 | /* and enable transmitter ready IRQ */ | ||
878 | intr_mask.trdy = 1; | ||
879 | REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); | ||
880 | } else { | ||
881 | start_dma(port, (unsigned char* volatile )port->outp, c); | ||
882 | } | ||
883 | } | ||
884 | spin_unlock_irqrestore(&port->lock, flags); | ||
885 | DEBUGWRITE(printk("w d%d c %lu NB\n", | ||
886 | port->port_nbr, count)); | ||
887 | return count; | ||
888 | } | ||
889 | |||
890 | /* Sleep until all sent */ | ||
891 | |||
892 | add_wait_queue(&port->out_wait_q, &wait); | ||
893 | set_current_state(TASK_INTERRUPTIBLE); | ||
894 | spin_lock_irqsave(&port->lock, flags); | ||
895 | if (!port->tr_running) { | ||
896 | if (!port->use_dma) { | ||
897 | reg_sser_rw_intr_mask intr_mask; | ||
898 | intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); | ||
899 | /* Start sender by writing data */ | ||
900 | send_word(port); | ||
901 | /* and enable transmitter ready IRQ */ | ||
902 | intr_mask.trdy = 1; | ||
903 | REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); | ||
904 | } else { | ||
905 | start_dma(port, port->outp, c); | ||
906 | } | ||
907 | } | ||
908 | spin_unlock_irqrestore(&port->lock, flags); | ||
909 | schedule(); | ||
910 | set_current_state(TASK_RUNNING); | ||
911 | remove_wait_queue(&port->out_wait_q, &wait); | ||
912 | if (signal_pending(current)) | ||
913 | { | ||
914 | return -EINTR; | ||
915 | } | ||
916 | DEBUGWRITE(printk("w d%d c %lu\n", port->port_nbr, count)); | ||
917 | return count; | ||
918 | } | ||
919 | |||
920 | static ssize_t sync_serial_read(struct file * file, char * buf, | ||
921 | size_t count, loff_t *ppos) | ||
922 | { | ||
923 | int dev = MINOR(file->f_dentry->d_inode->i_rdev); | ||
924 | int avail; | ||
925 | sync_port *port; | ||
926 | unsigned char* start; | ||
927 | unsigned char* end; | ||
928 | unsigned long flags; | ||
929 | |||
930 | if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) | ||
931 | { | ||
932 | DEBUG(printk("Invalid minor %d\n", dev)); | ||
933 | return -ENODEV; | ||
934 | } | ||
935 | port = &ports[dev]; | ||
936 | |||
937 | DEBUGREAD(printk("R%d c %d ri %lu wi %lu /%lu\n", dev, count, port->readp - port->flip, port->writep - port->flip, port->in_buffer_size)); | ||
938 | |||
939 | if (!port->started) | ||
940 | { | ||
941 | reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); | ||
942 | reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); | ||
943 | reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); | ||
944 | cfg.en = regk_sser_yes; | ||
945 | tr_cfg.tr_en = regk_sser_yes; | ||
946 | rec_cfg.rec_en = regk_sser_yes; | ||
947 | REG_WR(sser, port->regi_sser, rw_cfg, cfg); | ||
948 | REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); | ||
949 | REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); | ||
950 | port->started = 1; | ||
951 | } | ||
952 | |||
953 | |||
954 | /* Calculate number of available bytes */ | ||
955 | /* Save pointers to avoid that they are modified by interrupt */ | ||
956 | spin_lock_irqsave(&port->lock, flags); | ||
957 | start = (unsigned char*)port->readp; /* cast away volatile */ | ||
958 | end = (unsigned char*)port->writep; /* cast away volatile */ | ||
959 | spin_unlock_irqrestore(&port->lock, flags); | ||
960 | while ((start == end) && !port->full) /* No data */ | ||
961 | { | ||
962 | if (file->f_flags & O_NONBLOCK) | ||
963 | { | ||
964 | return -EAGAIN; | ||
965 | } | ||
966 | |||
967 | interruptible_sleep_on(&port->in_wait_q); | ||
968 | if (signal_pending(current)) | ||
969 | { | ||
970 | return -EINTR; | ||
971 | } | ||
972 | spin_lock_irqsave(&port->lock, flags); | ||
973 | start = (unsigned char*)port->readp; /* cast away volatile */ | ||
974 | end = (unsigned char*)port->writep; /* cast away volatile */ | ||
975 | spin_unlock_irqrestore(&port->lock, flags); | ||
976 | } | ||
977 | |||
978 | /* Lazy read, never return wrapped data. */ | ||
979 | if (port->full) | ||
980 | avail = port->in_buffer_size; | ||
981 | else if (end > start) | ||
982 | avail = end - start; | ||
983 | else | ||
984 | avail = port->flip + port->in_buffer_size - start; | ||
985 | |||
986 | count = count > avail ? avail : count; | ||
987 | if (copy_to_user(buf, start, count)) | ||
988 | return -EFAULT; | ||
989 | /* Disable interrupts while updating readp */ | ||
990 | spin_lock_irqsave(&port->lock, flags); | ||
991 | port->readp += count; | ||
992 | if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */ | ||
993 | port->readp = port->flip; | ||
994 | port->full = 0; | ||
995 | spin_unlock_irqrestore(&port->lock, flags); | ||
996 | DEBUGREAD(printk("r %d\n", count)); | ||
997 | return count; | ||
998 | } | ||
999 | |||
1000 | static void send_word(sync_port* port) | ||
1001 | { | ||
1002 | reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); | ||
1003 | reg_sser_rw_tr_data tr_data = {0}; | ||
1004 | |||
1005 | switch(tr_cfg.sample_size) | ||
1006 | { | ||
1007 | case 8: | ||
1008 | port->out_count--; | ||
1009 | tr_data.data = *port->outp++; | ||
1010 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | ||
1011 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | ||
1012 | port->outp = port->out_buffer; | ||
1013 | break; | ||
1014 | case 12: | ||
1015 | { | ||
1016 | int data = (*port->outp++) << 8; | ||
1017 | data |= *port->outp++; | ||
1018 | port->out_count-=2; | ||
1019 | tr_data.data = data; | ||
1020 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | ||
1021 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | ||
1022 | port->outp = port->out_buffer; | ||
1023 | } | ||
1024 | break; | ||
1025 | case 16: | ||
1026 | port->out_count-=2; | ||
1027 | tr_data.data = *(unsigned short *)port->outp; | ||
1028 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | ||
1029 | port->outp+=2; | ||
1030 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | ||
1031 | port->outp = port->out_buffer; | ||
1032 | break; | ||
1033 | case 24: | ||
1034 | port->out_count-=3; | ||
1035 | tr_data.data = *(unsigned short *)port->outp; | ||
1036 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | ||
1037 | port->outp+=2; | ||
1038 | tr_data.data = *port->outp++; | ||
1039 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | ||
1040 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | ||
1041 | port->outp = port->out_buffer; | ||
1042 | break; | ||
1043 | case 32: | ||
1044 | port->out_count-=4; | ||
1045 | tr_data.data = *(unsigned short *)port->outp; | ||
1046 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | ||
1047 | port->outp+=2; | ||
1048 | tr_data.data = *(unsigned short *)port->outp; | ||
1049 | REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); | ||
1050 | port->outp+=2; | ||
1051 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | ||
1052 | port->outp = port->out_buffer; | ||
1053 | break; | ||
1054 | } | ||
1055 | } | ||
1056 | |||
1057 | |||
1058 | static void start_dma(struct sync_port* port, const char* data, int count) | ||
1059 | { | ||
1060 | port->tr_running = 1; | ||
1061 | port->out_descr.buf = (char*)virt_to_phys((char*)data); | ||
1062 | port->out_descr.after = port->out_descr.buf + count; | ||
1063 | port->out_descr.eol = port->out_descr.intr = 1; | ||
1064 | |||
1065 | port->out_context.saved_data = (dma_descr_data*)virt_to_phys(&port->out_descr); | ||
1066 | port->out_context.saved_data_buf = port->out_descr.buf; | ||
1067 | |||
1068 | DMA_START_CONTEXT(port->regi_dmaout, virt_to_phys((char*)&port->out_context)); | ||
1069 | DEBUGTXINT(printk("dma %08lX c %d\n", (unsigned long)data, count)); | ||
1070 | } | ||
1071 | |||
1072 | static void start_dma_in(sync_port* port) | ||
1073 | { | ||
1074 | int i; | ||
1075 | char* buf; | ||
1076 | port->writep = port->flip; | ||
1077 | |||
1078 | if (port->writep > port->flip + port->in_buffer_size) | ||
1079 | { | ||
1080 | panic("Offset too large in sync serial driver\n"); | ||
1081 | return; | ||
1082 | } | ||
1083 | buf = (char*)virt_to_phys(port->in_buffer); | ||
1084 | for (i = 0; i < NUM_IN_DESCR; i++) { | ||
1085 | port->in_descr[i].buf = buf; | ||
1086 | port->in_descr[i].after = buf + port->inbufchunk; | ||
1087 | port->in_descr[i].intr = 1; | ||
1088 | port->in_descr[i].next = (dma_descr_data*)virt_to_phys(&port->in_descr[i+1]); | ||
1089 | port->in_descr[i].buf = buf; | ||
1090 | buf += port->inbufchunk; | ||
1091 | } | ||
1092 | /* Link the last descriptor to the first */ | ||
1093 | port->in_descr[i-1].next = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); | ||
1094 | port->in_descr[i-1].eol = regk_sser_yes; | ||
1095 | port->next_rx_desc = &port->in_descr[0]; | ||
1096 | port->prev_rx_desc = &port->in_descr[NUM_IN_DESCR - 1]; | ||
1097 | port->in_context.saved_data = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); | ||
1098 | port->in_context.saved_data_buf = port->in_descr[0].buf; | ||
1099 | DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context)); | ||
1100 | } | ||
1101 | |||
1102 | #ifdef SYNC_SER_DMA | ||
1103 | static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) | ||
1104 | { | ||
1105 | reg_dma_r_masked_intr masked; | ||
1106 | reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes}; | ||
1107 | int i; | ||
1108 | struct dma_descr_data *descr; | ||
1109 | unsigned int sentl; | ||
1110 | int found = 0; | ||
1111 | |||
1112 | for (i = 0; i < NUMBER_OF_PORTS; i++) | ||
1113 | { | ||
1114 | sync_port *port = &ports[i]; | ||
1115 | if (!port->enabled || !port->use_dma ) | ||
1116 | continue; | ||
1117 | |||
1118 | masked = REG_RD(dma, port->regi_dmaout, r_masked_intr); | ||
1119 | |||
1120 | if (masked.data) /* IRQ active for the port? */ | ||
1121 | { | ||
1122 | found = 1; | ||
1123 | /* Clear IRQ */ | ||
1124 | REG_WR(dma, port->regi_dmaout, rw_ack_intr, ack_intr); | ||
1125 | descr = &port->out_descr; | ||
1126 | sentl = descr->after - descr->buf; | ||
1127 | port->out_count -= sentl; | ||
1128 | port->outp += sentl; | ||
1129 | if (port->outp >= port->out_buffer + OUT_BUFFER_SIZE) | ||
1130 | port->outp = port->out_buffer; | ||
1131 | if (port->out_count) { | ||
1132 | int c; | ||
1133 | c = port->out_buffer + OUT_BUFFER_SIZE - port->outp; | ||
1134 | if (c > port->out_count) | ||
1135 | c = port->out_count; | ||
1136 | DEBUGTXINT(printk("tx_int DMAWRITE %i %i\n", sentl, c)); | ||
1137 | start_dma(port, port->outp, c); | ||
1138 | } else { | ||
1139 | DEBUGTXINT(printk("tx_int DMA stop %i\n", sentl)); | ||
1140 | port->tr_running = 0; | ||
1141 | } | ||
1142 | wake_up_interruptible(&port->out_wait_q); /* wake up the waiting process */ | ||
1143 | } | ||
1144 | } | ||
1145 | return IRQ_RETVAL(found); | ||
1146 | } /* tr_interrupt */ | ||
1147 | |||
1148 | static irqreturn_t rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) | ||
1149 | { | ||
1150 | reg_dma_r_masked_intr masked; | ||
1151 | reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes}; | ||
1152 | |||
1153 | int i; | ||
1154 | int found = 0; | ||
1155 | |||
1156 | for (i = 0; i < NUMBER_OF_PORTS; i++) | ||
1157 | { | ||
1158 | sync_port *port = &ports[i]; | ||
1159 | |||
1160 | if (!port->enabled || !port->use_dma ) | ||
1161 | continue; | ||
1162 | |||
1163 | masked = REG_RD(dma, port->regi_dmain, r_masked_intr); | ||
1164 | |||
1165 | if (masked.data) /* Descriptor interrupt */ | ||
1166 | { | ||
1167 | found = 1; | ||
1168 | while (REG_RD(dma, port->regi_dmain, rw_data) != | ||
1169 | virt_to_phys(port->next_rx_desc)) { | ||
1170 | |||
1171 | if (port->writep + port->inbufchunk > port->flip + port->in_buffer_size) { | ||
1172 | int first_size = port->flip + port->in_buffer_size - port->writep; | ||
1173 | memcpy((char*)port->writep, phys_to_virt((unsigned)port->next_rx_desc->buf), first_size); | ||
1174 | memcpy(port->flip, phys_to_virt((unsigned)port->next_rx_desc->buf+first_size), port->inbufchunk - first_size); | ||
1175 | port->writep = port->flip + port->inbufchunk - first_size; | ||
1176 | } else { | ||
1177 | memcpy((char*)port->writep, | ||
1178 | phys_to_virt((unsigned)port->next_rx_desc->buf), | ||
1179 | port->inbufchunk); | ||
1180 | port->writep += port->inbufchunk; | ||
1181 | if (port->writep >= port->flip + port->in_buffer_size) | ||
1182 | port->writep = port->flip; | ||
1183 | } | ||
1184 | if (port->writep == port->readp) | ||
1185 | { | ||
1186 | port->full = 1; | ||
1187 | } | ||
1188 | |||
1189 | port->next_rx_desc->eol = 0; | ||
1190 | port->prev_rx_desc->eol = 1; | ||
1191 | port->prev_rx_desc = phys_to_virt((unsigned)port->next_rx_desc); | ||
1192 | port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next); | ||
1193 | wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ | ||
1194 | DMA_CONTINUE(port->regi_dmain); | ||
1195 | REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr); | ||
1196 | |||
1197 | } | ||
1198 | } | ||
1199 | } | ||
1200 | return IRQ_RETVAL(found); | ||
1201 | } /* rx_interrupt */ | ||
1202 | #endif /* SYNC_SER_DMA */ | ||
1203 | |||
1204 | #ifdef SYNC_SER_MANUAL | ||
1205 | static irqreturn_t manual_interrupt(int irq, void *dev_id, struct pt_regs * regs) | ||
1206 | { | ||
1207 | int i; | ||
1208 | int found = 0; | ||
1209 | reg_sser_r_masked_intr masked; | ||
1210 | |||
1211 | for (i = 0; i < NUMBER_OF_PORTS; i++) | ||
1212 | { | ||
1213 | sync_port* port = &ports[i]; | ||
1214 | |||
1215 | if (!port->enabled || port->use_dma) | ||
1216 | { | ||
1217 | continue; | ||
1218 | } | ||
1219 | |||
1220 | masked = REG_RD(sser, port->regi_sser, r_masked_intr); | ||
1221 | if (masked.rdav) /* Data received? */ | ||
1222 | { | ||
1223 | reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); | ||
1224 | reg_sser_r_rec_data data = REG_RD(sser, port->regi_sser, r_rec_data); | ||
1225 | found = 1; | ||
1226 | /* Read data */ | ||
1227 | switch(rec_cfg.sample_size) | ||
1228 | { | ||
1229 | case 8: | ||
1230 | *port->writep++ = data.data & 0xff; | ||
1231 | break; | ||
1232 | case 12: | ||
1233 | *port->writep = (data.data & 0x0ff0) >> 4; | ||
1234 | *(port->writep + 1) = data.data & 0x0f; | ||
1235 | port->writep+=2; | ||
1236 | break; | ||
1237 | case 16: | ||
1238 | *(unsigned short*)port->writep = data.data; | ||
1239 | port->writep+=2; | ||
1240 | break; | ||
1241 | case 24: | ||
1242 | *(unsigned int*)port->writep = data.data; | ||
1243 | port->writep+=3; | ||
1244 | break; | ||
1245 | case 32: | ||
1246 | *(unsigned int*)port->writep = data.data; | ||
1247 | port->writep+=4; | ||
1248 | break; | ||
1249 | } | ||
1250 | |||
1251 | if (port->writep >= port->flip + port->in_buffer_size) /* Wrap? */ | ||
1252 | port->writep = port->flip; | ||
1253 | if (port->writep == port->readp) { | ||
1254 | /* receive buffer overrun, discard oldest data | ||
1255 | */ | ||
1256 | port->readp++; | ||
1257 | if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */ | ||
1258 | port->readp = port->flip; | ||
1259 | } | ||
1260 | if (sync_data_avail(port) >= port->inbufchunk) | ||
1261 | wake_up_interruptible(&port->in_wait_q); /* Wake up application */ | ||
1262 | } | ||
1263 | |||
1264 | if (masked.trdy) /* Transmitter ready? */ | ||
1265 | { | ||
1266 | found = 1; | ||
1267 | if (port->out_count > 0) /* More data to send */ | ||
1268 | send_word(port); | ||
1269 | else /* transmission finished */ | ||
1270 | { | ||
1271 | reg_sser_rw_intr_mask intr_mask; | ||
1272 | intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); | ||
1273 | intr_mask.trdy = 0; | ||
1274 | REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); | ||
1275 | wake_up_interruptible(&port->out_wait_q); /* Wake up application */ | ||
1276 | } | ||
1277 | } | ||
1278 | } | ||
1279 | return IRQ_RETVAL(found); | ||
1280 | } | ||
1281 | #endif | ||
1282 | |||
1283 | module_init(etrax_sync_serial_init); | ||