Commit | Line | Data |
---|---|---|
b5c6c1a7 CM |
1 | /* |
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation, version 2. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, but | |
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
11 | * NON INFRINGEMENT. See the GNU General Public License for | |
12 | * more details. | |
13 | * | |
14 | * TILEGx UART driver. | |
15 | */ | |
16 | ||
17 | #include <linux/delay.h> | |
18 | #include <linux/init.h> | |
19 | #include <linux/interrupt.h> | |
20 | #include <linux/io.h> | |
21 | #include <linux/irq.h> | |
22 | #include <linux/module.h> | |
23 | #include <linux/serial_core.h> | |
24 | #include <linux/tty.h> | |
25 | #include <linux/tty_flip.h> | |
26 | ||
27 | #include <gxio/common.h> | |
28 | #include <gxio/iorpc_globals.h> | |
29 | #include <gxio/iorpc_uart.h> | |
30 | #include <gxio/kiorpc.h> | |
31 | ||
32 | #include <hv/drv_uart_intf.h> | |
33 | ||
34 | /* | |
35 | * Use device name ttyS, major 4, minor 64-65. | |
36 | * This is the usual serial port name, 8250 conventional range. | |
37 | */ | |
38 | #define TILEGX_UART_MAJOR TTY_MAJOR | |
39 | #define TILEGX_UART_MINOR 64 | |
40 | #define TILEGX_UART_NAME "ttyS" | |
41 | #define DRIVER_NAME_STRING "TILEGx_Serial" | |
42 | #define TILEGX_UART_REF_CLK 125000000; /* REF_CLK is always 125 MHz. */ | |
43 | ||
44 | struct tile_uart_port { | |
45 | /* UART port. */ | |
46 | struct uart_port uart; | |
47 | ||
48 | /* GXIO device context. */ | |
49 | gxio_uart_context_t context; | |
50 | ||
51 | /* UART access mutex. */ | |
52 | struct mutex mutex; | |
53 | ||
54 | /* CPU receiving interrupts. */ | |
55 | int irq_cpu; | |
56 | }; | |
57 | ||
58 | static struct tile_uart_port tile_uart_ports[TILEGX_UART_NR]; | |
59 | static struct uart_driver tilegx_uart_driver; | |
60 | ||
61 | ||
62 | /* | |
63 | * Read UART rx fifo, and insert the chars into tty buffer. | |
64 | */ | |
65 | static void receive_chars(struct tile_uart_port *tile_uart, | |
66 | struct tty_struct *tty) | |
67 | { | |
68 | int i; | |
69 | char c; | |
70 | UART_FIFO_COUNT_t count; | |
71 | gxio_uart_context_t *context = &tile_uart->context; | |
72 | struct tty_port *port = tty->port; | |
73 | ||
74 | count.word = gxio_uart_read(context, UART_FIFO_COUNT); | |
75 | for (i = 0; i < count.rfifo_count; i++) { | |
76 | c = (char)gxio_uart_read(context, UART_RECEIVE_DATA); | |
77 | tty_insert_flip_char(port, c, TTY_NORMAL); | |
78 | } | |
79 | } | |
80 | ||
81 | ||
82 | /* | |
83 | * Drain the Rx FIFO, called by interrupt handler. | |
84 | */ | |
85 | static void handle_receive(struct tile_uart_port *tile_uart) | |
86 | { | |
87 | struct tty_port *port = &tile_uart->uart.state->port; | |
88 | struct tty_struct *tty = tty_port_tty_get(port); | |
89 | gxio_uart_context_t *context = &tile_uart->context; | |
90 | ||
91 | if (!tty) | |
92 | return; | |
93 | ||
94 | /* First read UART rx fifo. */ | |
95 | receive_chars(tile_uart, tty); | |
96 | ||
97 | /* Reset RFIFO_WE interrupt. */ | |
98 | gxio_uart_write(context, UART_INTERRUPT_STATUS, | |
99 | UART_INTERRUPT_MASK__RFIFO_WE_MASK); | |
100 | ||
101 | /* Final read, if any chars comes between the first read and | |
102 | * the interrupt reset. | |
103 | */ | |
104 | receive_chars(tile_uart, tty); | |
105 | ||
106 | spin_unlock(&tile_uart->uart.lock); | |
107 | tty_flip_buffer_push(port); | |
108 | spin_lock(&tile_uart->uart.lock); | |
109 | tty_kref_put(tty); | |
110 | } | |
111 | ||
112 | ||
113 | /* | |
114 | * Push one char to UART Write FIFO. | |
115 | * Return 0 on success, -1 if write filo is full. | |
116 | */ | |
117 | static int tilegx_putchar(gxio_uart_context_t *context, char c) | |
118 | { | |
119 | UART_FLAG_t flag; | |
120 | flag.word = gxio_uart_read(context, UART_FLAG); | |
121 | if (flag.wfifo_full) | |
122 | return -1; | |
123 | ||
124 | gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c); | |
125 | return 0; | |
126 | } | |
127 | ||
128 | ||
129 | /* | |
130 | * Send chars to UART Write FIFO; called by interrupt handler. | |
131 | */ | |
132 | static void handle_transmit(struct tile_uart_port *tile_uart) | |
133 | { | |
134 | unsigned char ch; | |
135 | struct uart_port *port; | |
136 | struct circ_buf *xmit; | |
137 | gxio_uart_context_t *context = &tile_uart->context; | |
138 | ||
139 | /* First reset WFIFO_RE interrupt. */ | |
140 | gxio_uart_write(context, UART_INTERRUPT_STATUS, | |
141 | UART_INTERRUPT_MASK__WFIFO_RE_MASK); | |
142 | ||
143 | port = &tile_uart->uart; | |
144 | xmit = &port->state->xmit; | |
145 | if (port->x_char) { | |
146 | if (tilegx_putchar(context, port->x_char)) | |
147 | return; | |
148 | port->x_char = 0; | |
149 | port->icount.tx++; | |
150 | } | |
151 | ||
152 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) | |
153 | return; | |
154 | ||
155 | while (!uart_circ_empty(xmit)) { | |
156 | ch = xmit->buf[xmit->tail]; | |
157 | if (tilegx_putchar(context, ch)) | |
158 | break; | |
159 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | |
160 | port->icount.tx++; | |
161 | } | |
162 | ||
163 | /* Reset WFIFO_RE interrupt. */ | |
164 | gxio_uart_write(context, UART_INTERRUPT_STATUS, | |
165 | UART_INTERRUPT_MASK__WFIFO_RE_MASK); | |
166 | ||
167 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | |
168 | uart_write_wakeup(port); | |
169 | } | |
170 | ||
171 | ||
172 | /* | |
173 | * UART Interrupt handler. | |
174 | */ | |
175 | static irqreturn_t tilegx_interrupt(int irq, void *dev_id) | |
176 | { | |
177 | unsigned long flags; | |
178 | UART_INTERRUPT_STATUS_t intr_stat; | |
179 | struct tile_uart_port *tile_uart; | |
180 | gxio_uart_context_t *context; | |
181 | struct uart_port *port = dev_id; | |
182 | irqreturn_t ret = IRQ_NONE; | |
183 | ||
184 | spin_lock_irqsave(&port->lock, flags); | |
185 | ||
186 | tile_uart = container_of(port, struct tile_uart_port, uart); | |
187 | context = &tile_uart->context; | |
188 | intr_stat.word = gxio_uart_read(context, UART_INTERRUPT_STATUS); | |
189 | ||
190 | if (intr_stat.rfifo_we) { | |
191 | handle_receive(tile_uart); | |
192 | ret = IRQ_HANDLED; | |
193 | } | |
194 | if (intr_stat.wfifo_re) { | |
195 | handle_transmit(tile_uart); | |
196 | ret = IRQ_HANDLED; | |
197 | } | |
198 | ||
199 | spin_unlock_irqrestore(&port->lock, flags); | |
200 | return ret; | |
201 | } | |
202 | ||
203 | ||
204 | /* | |
205 | * Return TIOCSER_TEMT when transmitter FIFO is empty. | |
206 | */ | |
207 | static u_int tilegx_tx_empty(struct uart_port *port) | |
208 | { | |
209 | int ret; | |
210 | UART_FLAG_t flag; | |
211 | struct tile_uart_port *tile_uart; | |
212 | gxio_uart_context_t *context; | |
213 | ||
214 | tile_uart = container_of(port, struct tile_uart_port, uart); | |
215 | if (!mutex_trylock(&tile_uart->mutex)) | |
216 | return 0; | |
217 | context = &tile_uart->context; | |
218 | ||
219 | flag.word = gxio_uart_read(context, UART_FLAG); | |
220 | ret = (flag.wfifo_empty) ? TIOCSER_TEMT : 0; | |
221 | mutex_unlock(&tile_uart->mutex); | |
222 | ||
223 | return ret; | |
224 | } | |
225 | ||
226 | ||
227 | /* | |
228 | * Set state of the modem control output lines. | |
229 | */ | |
230 | static void tilegx_set_mctrl(struct uart_port *port, u_int mctrl) | |
231 | { | |
232 | /* N/A */ | |
233 | } | |
234 | ||
235 | ||
236 | /* | |
237 | * Get state of the modem control input lines. | |
238 | */ | |
239 | static u_int tilegx_get_mctrl(struct uart_port *port) | |
240 | { | |
241 | return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; | |
242 | } | |
243 | ||
244 | ||
245 | /* | |
246 | * Stop transmitting. | |
247 | */ | |
248 | static void tilegx_stop_tx(struct uart_port *port) | |
249 | { | |
250 | /* N/A */ | |
251 | } | |
252 | ||
253 | ||
254 | /* | |
255 | * Start transmitting. | |
256 | */ | |
257 | static void tilegx_start_tx(struct uart_port *port) | |
258 | { | |
259 | unsigned char ch; | |
260 | struct circ_buf *xmit; | |
261 | struct tile_uart_port *tile_uart; | |
262 | gxio_uart_context_t *context; | |
263 | ||
264 | tile_uart = container_of(port, struct tile_uart_port, uart); | |
265 | if (!mutex_trylock(&tile_uart->mutex)) | |
266 | return; | |
267 | context = &tile_uart->context; | |
268 | xmit = &port->state->xmit; | |
269 | if (port->x_char) { | |
270 | if (tilegx_putchar(context, port->x_char)) | |
271 | return; | |
272 | port->x_char = 0; | |
273 | port->icount.tx++; | |
274 | } | |
275 | ||
276 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { | |
277 | mutex_unlock(&tile_uart->mutex); | |
278 | return; | |
279 | } | |
280 | ||
281 | while (!uart_circ_empty(xmit)) { | |
282 | ch = xmit->buf[xmit->tail]; | |
283 | if (tilegx_putchar(context, ch)) | |
284 | break; | |
285 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | |
286 | port->icount.tx++; | |
287 | } | |
288 | ||
289 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | |
290 | uart_write_wakeup(port); | |
291 | ||
292 | mutex_unlock(&tile_uart->mutex); | |
293 | } | |
294 | ||
295 | ||
296 | /* | |
297 | * Stop receiving - port is in process of being closed. | |
298 | */ | |
299 | static void tilegx_stop_rx(struct uart_port *port) | |
300 | { | |
301 | int err; | |
302 | struct tile_uart_port *tile_uart; | |
303 | gxio_uart_context_t *context; | |
304 | int cpu; | |
305 | ||
306 | tile_uart = container_of(port, struct tile_uart_port, uart); | |
307 | if (!mutex_trylock(&tile_uart->mutex)) | |
308 | return; | |
309 | ||
310 | context = &tile_uart->context; | |
311 | cpu = tile_uart->irq_cpu; | |
312 | err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), | |
313 | KERNEL_PL, -1); | |
314 | mutex_unlock(&tile_uart->mutex); | |
315 | } | |
316 | ||
b5c6c1a7 CM |
317 | /* |
318 | * Control the transmission of a break signal. | |
319 | */ | |
320 | static void tilegx_break_ctl(struct uart_port *port, int break_state) | |
321 | { | |
322 | /* N/A */ | |
323 | } | |
324 | ||
325 | ||
326 | /* | |
327 | * Perform initialization and enable port for reception. | |
328 | */ | |
329 | static int tilegx_startup(struct uart_port *port) | |
330 | { | |
331 | struct tile_uart_port *tile_uart; | |
332 | gxio_uart_context_t *context; | |
333 | int ret = 0; | |
334 | int cpu = raw_smp_processor_id(); /* pick an arbitrary cpu */ | |
335 | ||
336 | tile_uart = container_of(port, struct tile_uart_port, uart); | |
337 | if (mutex_lock_interruptible(&tile_uart->mutex)) | |
338 | return -EBUSY; | |
339 | context = &tile_uart->context; | |
340 | ||
341 | /* Now open the hypervisor device if we haven't already. */ | |
342 | if (context->fd < 0) { | |
343 | UART_INTERRUPT_MASK_t intr_mask; | |
344 | ||
345 | /* Initialize UART device. */ | |
346 | ret = gxio_uart_init(context, port->line); | |
347 | if (ret) { | |
348 | ret = -ENXIO; | |
349 | goto err; | |
350 | } | |
351 | ||
352 | /* Create our IRQs. */ | |
651fb139 TG |
353 | port->irq = irq_alloc_hwirq(-1); |
354 | if (!port->irq) | |
b5c6c1a7 CM |
355 | goto err_uart_dest; |
356 | tile_irq_activate(port->irq, TILE_IRQ_PERCPU); | |
357 | ||
358 | /* Register our IRQs. */ | |
359 | ret = request_irq(port->irq, tilegx_interrupt, 0, | |
360 | tilegx_uart_driver.driver_name, port); | |
361 | if (ret) | |
362 | goto err_dest_irq; | |
363 | ||
364 | /* Request that the hardware start sending us interrupts. */ | |
365 | tile_uart->irq_cpu = cpu; | |
366 | ret = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), | |
367 | KERNEL_PL, port->irq); | |
368 | if (ret) | |
369 | goto err_free_irq; | |
370 | ||
371 | /* Enable UART Tx/Rx Interrupt. */ | |
372 | intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK); | |
373 | intr_mask.wfifo_re = 0; | |
374 | intr_mask.rfifo_we = 0; | |
375 | gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word); | |
376 | ||
377 | /* Reset the Tx/Rx interrupt in case it's set. */ | |
378 | gxio_uart_write(context, UART_INTERRUPT_STATUS, | |
379 | UART_INTERRUPT_MASK__WFIFO_RE_MASK | | |
380 | UART_INTERRUPT_MASK__RFIFO_WE_MASK); | |
381 | } | |
382 | ||
383 | mutex_unlock(&tile_uart->mutex); | |
384 | return ret; | |
385 | ||
386 | err_free_irq: | |
387 | free_irq(port->irq, port); | |
388 | err_dest_irq: | |
651fb139 | 389 | irq_free_hwirq(port->irq); |
b5c6c1a7 CM |
390 | err_uart_dest: |
391 | gxio_uart_destroy(context); | |
392 | ret = -ENXIO; | |
393 | err: | |
394 | mutex_unlock(&tile_uart->mutex); | |
395 | return ret; | |
396 | } | |
397 | ||
398 | ||
399 | /* | |
400 | * Release kernel resources if it is the last close, disable the port, | |
401 | * free IRQ and close the port. | |
402 | */ | |
403 | static void tilegx_shutdown(struct uart_port *port) | |
404 | { | |
405 | int err; | |
406 | UART_INTERRUPT_MASK_t intr_mask; | |
407 | struct tile_uart_port *tile_uart; | |
408 | gxio_uart_context_t *context; | |
409 | int cpu; | |
410 | ||
411 | tile_uart = container_of(port, struct tile_uart_port, uart); | |
412 | if (mutex_lock_interruptible(&tile_uart->mutex)) | |
413 | return; | |
414 | context = &tile_uart->context; | |
415 | ||
416 | /* Disable UART Tx/Rx Interrupt. */ | |
417 | intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK); | |
418 | intr_mask.wfifo_re = 1; | |
419 | intr_mask.rfifo_we = 1; | |
420 | gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word); | |
421 | ||
422 | /* Request that the hardware stop sending us interrupts. */ | |
423 | cpu = tile_uart->irq_cpu; | |
424 | err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), | |
425 | KERNEL_PL, -1); | |
426 | ||
427 | if (port->irq > 0) { | |
428 | free_irq(port->irq, port); | |
651fb139 | 429 | irq_free_hwirq(port->irq); |
b5c6c1a7 CM |
430 | port->irq = 0; |
431 | } | |
432 | ||
433 | gxio_uart_destroy(context); | |
434 | ||
435 | mutex_unlock(&tile_uart->mutex); | |
436 | } | |
437 | ||
438 | ||
439 | /* | |
440 | * Flush the buffer. | |
441 | */ | |
442 | static void tilegx_flush_buffer(struct uart_port *port) | |
443 | { | |
444 | /* N/A */ | |
445 | } | |
446 | ||
447 | ||
448 | /* | |
449 | * Change the port parameters. | |
450 | */ | |
451 | static void tilegx_set_termios(struct uart_port *port, | |
452 | struct ktermios *termios, struct ktermios *old) | |
453 | { | |
454 | int err; | |
455 | UART_DIVISOR_t divisor; | |
456 | UART_TYPE_t type; | |
457 | unsigned int baud; | |
458 | struct tile_uart_port *tile_uart; | |
459 | gxio_uart_context_t *context; | |
460 | ||
461 | tile_uart = container_of(port, struct tile_uart_port, uart); | |
462 | if (!mutex_trylock(&tile_uart->mutex)) | |
463 | return; | |
464 | context = &tile_uart->context; | |
465 | ||
466 | /* Open the hypervisor device if we haven't already. */ | |
467 | if (context->fd < 0) { | |
468 | err = gxio_uart_init(context, port->line); | |
469 | if (err) { | |
470 | mutex_unlock(&tile_uart->mutex); | |
471 | return; | |
472 | } | |
473 | } | |
474 | ||
475 | divisor.word = gxio_uart_read(context, UART_DIVISOR); | |
476 | type.word = gxio_uart_read(context, UART_TYPE); | |
477 | ||
478 | /* Divisor. */ | |
479 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); | |
480 | divisor.divisor = uart_get_divisor(port, baud); | |
481 | ||
482 | /* Byte size. */ | |
483 | if ((termios->c_cflag & CSIZE) == CS7) | |
484 | type.dbits = UART_TYPE__DBITS_VAL_SEVEN_DBITS; | |
485 | else | |
486 | type.dbits = UART_TYPE__DBITS_VAL_EIGHT_DBITS; | |
487 | ||
488 | /* Parity. */ | |
489 | if (termios->c_cflag & PARENB) { | |
490 | /* Mark or Space parity. */ | |
491 | if (termios->c_cflag & CMSPAR) | |
492 | if (termios->c_cflag & PARODD) | |
493 | type.ptype = UART_TYPE__PTYPE_VAL_MARK; | |
494 | else | |
495 | type.ptype = UART_TYPE__PTYPE_VAL_SPACE; | |
496 | else if (termios->c_cflag & PARODD) | |
497 | type.ptype = UART_TYPE__PTYPE_VAL_ODD; | |
498 | else | |
499 | type.ptype = UART_TYPE__PTYPE_VAL_EVEN; | |
500 | } else | |
501 | type.ptype = UART_TYPE__PTYPE_VAL_NONE; | |
502 | ||
503 | /* Stop bits. */ | |
504 | if (termios->c_cflag & CSTOPB) | |
505 | type.sbits = UART_TYPE__SBITS_VAL_TWO_SBITS; | |
506 | else | |
507 | type.sbits = UART_TYPE__SBITS_VAL_ONE_SBITS; | |
508 | ||
509 | /* Set the uart paramters. */ | |
510 | gxio_uart_write(context, UART_DIVISOR, divisor.word); | |
511 | gxio_uart_write(context, UART_TYPE, type.word); | |
512 | ||
513 | mutex_unlock(&tile_uart->mutex); | |
514 | } | |
515 | ||
516 | ||
517 | /* | |
518 | * Return string describing the specified port. | |
519 | */ | |
520 | static const char *tilegx_type(struct uart_port *port) | |
521 | { | |
522 | return port->type == PORT_TILEGX ? DRIVER_NAME_STRING : NULL; | |
523 | } | |
524 | ||
525 | ||
526 | /* | |
527 | * Release the resources being used by 'port'. | |
528 | */ | |
529 | static void tilegx_release_port(struct uart_port *port) | |
530 | { | |
531 | /* Nothing to release. */ | |
532 | } | |
533 | ||
534 | ||
535 | /* | |
536 | * Request the resources being used by 'port'. | |
537 | */ | |
538 | static int tilegx_request_port(struct uart_port *port) | |
539 | { | |
540 | /* Always present. */ | |
541 | return 0; | |
542 | } | |
543 | ||
544 | ||
545 | /* | |
546 | * Configure/autoconfigure the port. | |
547 | */ | |
548 | static void tilegx_config_port(struct uart_port *port, int flags) | |
549 | { | |
550 | if (flags & UART_CONFIG_TYPE) | |
551 | port->type = PORT_TILEGX; | |
552 | } | |
553 | ||
554 | ||
555 | /* | |
556 | * Verify the new serial_struct (for TIOCSSERIAL). | |
557 | */ | |
558 | static int tilegx_verify_port(struct uart_port *port, | |
559 | struct serial_struct *ser) | |
560 | { | |
561 | if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_TILEGX)) | |
562 | return -EINVAL; | |
563 | ||
564 | return 0; | |
565 | } | |
566 | ||
567 | #ifdef CONFIG_CONSOLE_POLL | |
568 | ||
569 | /* | |
570 | * Console polling routines for writing and reading from the uart while | |
571 | * in an interrupt or debug context. | |
572 | */ | |
573 | ||
574 | static int tilegx_poll_get_char(struct uart_port *port) | |
575 | { | |
576 | UART_FIFO_COUNT_t count; | |
577 | gxio_uart_context_t *context; | |
578 | struct tile_uart_port *tile_uart; | |
579 | ||
580 | tile_uart = container_of(port, struct tile_uart_port, uart); | |
581 | context = &tile_uart->context; | |
582 | count.word = gxio_uart_read(context, UART_FIFO_COUNT); | |
583 | if (count.rfifo_count == 0) | |
584 | return NO_POLL_CHAR; | |
585 | return (char)gxio_uart_read(context, UART_RECEIVE_DATA); | |
586 | } | |
587 | ||
588 | static void tilegx_poll_put_char(struct uart_port *port, unsigned char c) | |
589 | { | |
590 | gxio_uart_context_t *context; | |
591 | struct tile_uart_port *tile_uart; | |
592 | ||
593 | tile_uart = container_of(port, struct tile_uart_port, uart); | |
594 | context = &tile_uart->context; | |
595 | gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c); | |
596 | } | |
597 | ||
598 | #endif /* CONFIG_CONSOLE_POLL */ | |
599 | ||
600 | ||
601 | static const struct uart_ops tilegx_ops = { | |
602 | .tx_empty = tilegx_tx_empty, | |
603 | .set_mctrl = tilegx_set_mctrl, | |
604 | .get_mctrl = tilegx_get_mctrl, | |
605 | .stop_tx = tilegx_stop_tx, | |
606 | .start_tx = tilegx_start_tx, | |
607 | .stop_rx = tilegx_stop_rx, | |
b5c6c1a7 CM |
608 | .break_ctl = tilegx_break_ctl, |
609 | .startup = tilegx_startup, | |
610 | .shutdown = tilegx_shutdown, | |
611 | .flush_buffer = tilegx_flush_buffer, | |
612 | .set_termios = tilegx_set_termios, | |
613 | .type = tilegx_type, | |
614 | .release_port = tilegx_release_port, | |
615 | .request_port = tilegx_request_port, | |
616 | .config_port = tilegx_config_port, | |
617 | .verify_port = tilegx_verify_port, | |
618 | #ifdef CONFIG_CONSOLE_POLL | |
619 | .poll_get_char = tilegx_poll_get_char, | |
620 | .poll_put_char = tilegx_poll_put_char, | |
621 | #endif | |
622 | }; | |
623 | ||
624 | ||
625 | static void tilegx_init_ports(void) | |
626 | { | |
627 | int i; | |
628 | struct uart_port *port; | |
629 | ||
630 | for (i = 0; i < TILEGX_UART_NR; i++) { | |
631 | port = &tile_uart_ports[i].uart; | |
632 | port->ops = &tilegx_ops; | |
633 | port->line = i; | |
634 | port->type = PORT_TILEGX; | |
635 | port->uartclk = TILEGX_UART_REF_CLK; | |
636 | port->flags = UPF_BOOT_AUTOCONF; | |
637 | ||
638 | tile_uart_ports[i].context.fd = -1; | |
639 | mutex_init(&tile_uart_ports[i].mutex); | |
640 | } | |
641 | } | |
642 | ||
643 | ||
644 | static struct uart_driver tilegx_uart_driver = { | |
645 | .owner = THIS_MODULE, | |
646 | .driver_name = DRIVER_NAME_STRING, | |
647 | .dev_name = TILEGX_UART_NAME, | |
648 | .major = TILEGX_UART_MAJOR, | |
649 | .minor = TILEGX_UART_MINOR, | |
650 | .nr = TILEGX_UART_NR, | |
651 | }; | |
652 | ||
653 | ||
654 | static int __init tilegx_init(void) | |
655 | { | |
656 | int i; | |
657 | int ret; | |
658 | struct tty_driver *tty_drv; | |
659 | ||
660 | ret = uart_register_driver(&tilegx_uart_driver); | |
661 | if (ret) | |
662 | return ret; | |
663 | tty_drv = tilegx_uart_driver.tty_driver; | |
664 | tty_drv->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; | |
665 | tty_drv->init_termios.c_ispeed = 115200; | |
666 | tty_drv->init_termios.c_ospeed = 115200; | |
667 | ||
668 | tilegx_init_ports(); | |
669 | ||
670 | for (i = 0; i < TILEGX_UART_NR; i++) { | |
671 | struct uart_port *port = &tile_uart_ports[i].uart; | |
672 | ret = uart_add_one_port(&tilegx_uart_driver, port); | |
673 | } | |
674 | ||
675 | return 0; | |
676 | } | |
677 | ||
678 | ||
679 | static void __exit tilegx_exit(void) | |
680 | { | |
681 | int i; | |
682 | struct uart_port *port; | |
683 | ||
684 | for (i = 0; i < TILEGX_UART_NR; i++) { | |
685 | port = &tile_uart_ports[i].uart; | |
686 | uart_remove_one_port(&tilegx_uart_driver, port); | |
687 | } | |
688 | ||
689 | uart_unregister_driver(&tilegx_uart_driver); | |
690 | } | |
691 | ||
692 | ||
693 | module_init(tilegx_init); | |
694 | module_exit(tilegx_exit); | |
695 | ||
696 | MODULE_AUTHOR("Tilera Corporation"); | |
697 | MODULE_DESCRIPTION("TILEGx serial port driver"); | |
698 | MODULE_LICENSE("GPL"); |