2 * linux/drivers/char/serial_21285.c
4 * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
6 * Based on drivers/char/serial.c
9 #include <linux/config.h>
10 #include <linux/module.h>
11 #include <linux/errno.h>
12 #include <linux/signal.h>
13 #include <linux/sched.h>
14 #include <linux/interrupt.h>
15 #include <linux/tty.h>
16 #include <linux/tty_flip.h>
17 #include <linux/serial.h>
18 #include <linux/major.h>
19 #include <linux/ptrace.h>
20 #include <linux/ioport.h>
22 #include <linux/malloc.h>
23 #include <linux/init.h>
24 #include <linux/console.h>
28 #include <asm/uaccess.h>
29 #include <asm/dec21285.h>
30 #include <asm/hardware.h>
32 #define BAUD_BASE (mem_fclk_21285/64)
34 #define SERIAL_21285_NAME "ttyFB"
35 #define SERIAL_21285_MAJOR 204
36 #define SERIAL_21285_MINOR 4
38 #define SERIAL_21285_AUXNAME "cuafb"
39 #define SERIAL_21285_AUXMAJOR 205
40 #define SERIAL_21285_AUXMINOR 4
42 static struct tty_driver rs285_driver
, callout_driver
;
43 static int rs285_refcount
;
44 static struct tty_struct
*rs285_table
[1];
46 static struct termios
*rs285_termios
[1];
47 static struct termios
*rs285_termios_locked
[1];
49 static char wbuf
[1000], *putp
= wbuf
, *getp
= wbuf
, x_char
;
50 static struct tty_struct
*rs285_tty
;
51 static int rs285_use_count
;
53 static int rs285_write_room(struct tty_struct
*tty
)
55 return putp
>= getp
? (sizeof(wbuf
) - (long) putp
+ (long) getp
) : ((long) getp
- (long) putp
- 1);
58 static void rs285_rx_int(int irq
, void *dev_id
, struct pt_regs
*regs
)
61 disable_irq(IRQ_CONRX
);
64 while (!(*CSR_UARTFLG
& 0x10)) {
69 tty_insert_flip_char(rs285_tty
, 0, TTY_OVERRUN
);
74 tty_insert_flip_char(rs285_tty
, ch
, flag
);
76 tty_flip_buffer_push(rs285_tty
);
79 static void rs285_send_xchar(struct tty_struct
*tty
, char ch
)
82 enable_irq(IRQ_CONTX
);
85 static void rs285_throttle(struct tty_struct
*tty
)
88 rs285_send_xchar(tty
, STOP_CHAR(tty
));
91 static void rs285_unthrottle(struct tty_struct
*tty
)
97 rs285_send_xchar(tty
, START_CHAR(tty
));
101 static void rs285_tx_int(int irq
, void *dev_id
, struct pt_regs
*regs
)
103 while (!(*CSR_UARTFLG
& 0x20)) {
105 *CSR_UARTDR
= x_char
;
110 disable_irq(IRQ_CONTX
);
114 if (++getp
>= wbuf
+ sizeof(wbuf
))
118 wake_up_interruptible(&rs285_tty
->write_wait
);
121 static inline int rs285_xmit(int ch
)
123 if (putp
+ 1 == getp
|| (putp
+ 1 == wbuf
+ sizeof(wbuf
) && getp
== wbuf
))
126 if (++putp
>= wbuf
+ sizeof(wbuf
))
128 enable_irq(IRQ_CONTX
);
132 static int rs285_write(struct tty_struct
*tty
, int from_user
,
133 const u_char
* buf
, int count
)
137 if (from_user
&& verify_area(VERIFY_READ
, buf
, count
))
140 for (i
= 0; i
< count
; i
++) {
143 __get_user(ch
, buf
+ i
);
152 static void rs285_put_char(struct tty_struct
*tty
, u_char ch
)
157 static int rs285_chars_in_buffer(struct tty_struct
*tty
)
159 return sizeof(wbuf
) - rs285_write_room(tty
);
162 static void rs285_flush_buffer(struct tty_struct
*tty
)
164 disable_irq(IRQ_CONTX
);
167 enable_irq(IRQ_CONTX
);
170 static inline void rs285_set_cflag(int cflag
)
172 int h_lcr
, baud
, quot
;
174 switch (cflag
& CSIZE
) {
193 if (!(cflag
& PARODD
))
196 switch (cflag
& CBAUD
) {
197 case B200
: baud
= 200; break;
198 case B300
: baud
= 300; break;
199 case B1200
: baud
= 1200; break;
200 case B1800
: baud
= 1800; break;
201 case B2400
: baud
= 2400; break;
202 case B4800
: baud
= 4800; break;
204 case B9600
: baud
= 9600; break;
205 case B19200
: baud
= 19200; break;
206 case B38400
: baud
= 38400; break;
207 case B57600
: baud
= 57600; break;
208 case B115200
: baud
= 115200; break;
212 * The documented expression for selecting the divisor is:
213 * BAUD_BASE / baud - 1
214 * However, typically BAUD_BASE is not divisible by baud, so
215 * we want to select the divisor that gives us the minimum
216 * error. Therefore, we want:
217 * int(BAUD_BASE / baud - 0.5) ->
218 * int(BAUD_BASE / baud - (baud >> 1) / baud) ->
219 * int((BAUD_BASE - (baud >> 1)) / baud)
221 quot
= (BAUD_BASE
- (baud
>> 1)) / baud
;
224 *CSR_L_UBRLCR
= quot
& 0xff;
225 *CSR_M_UBRLCR
= (quot
>> 8) & 0x0f;
226 *CSR_H_UBRLCR
= h_lcr
;
230 static void rs285_set_termios(struct tty_struct
*tty
, struct termios
*old
)
232 if (old
&& tty
->termios
->c_cflag
== old
->c_cflag
)
234 rs285_set_cflag(tty
->termios
->c_cflag
);
238 static void rs285_stop(struct tty_struct
*tty
)
240 disable_irq(IRQ_CONTX
);
243 static void rs285_start(struct tty_struct
*tty
)
245 enable_irq(IRQ_CONTX
);
248 static void rs285_wait_until_sent(struct tty_struct
*tty
, int timeout
)
250 int orig_jiffies
= jiffies
;
251 while (*CSR_UARTFLG
& 8) {
252 current
->state
= TASK_INTERRUPTIBLE
;
254 if (signal_pending(current
))
256 if (timeout
&& time_after(jiffies
, orig_jiffies
+ timeout
))
259 current
->state
= TASK_RUNNING
;
262 static int rs285_open(struct tty_struct
*tty
, struct file
*filp
)
267 line
= MINOR(tty
->device
) - tty
->driver
.minor_start
;
273 tty
->driver_data
= NULL
;
277 enable_irq(IRQ_CONRX
);
282 static void rs285_close(struct tty_struct
*tty
, struct file
*filp
)
284 if (!--rs285_use_count
) {
285 rs285_wait_until_sent(tty
, 0);
286 disable_irq(IRQ_CONRX
);
287 disable_irq(IRQ_CONTX
);
293 static int __init
rs285_init(void)
297 if (machine_is_personal_server())
300 rs285_driver
.magic
= TTY_DRIVER_MAGIC
;
301 rs285_driver
.driver_name
= "serial_21285";
302 rs285_driver
.name
= SERIAL_21285_NAME
;
303 rs285_driver
.major
= SERIAL_21285_MAJOR
;
304 rs285_driver
.minor_start
= SERIAL_21285_MINOR
;
305 rs285_driver
.num
= 1;
306 rs285_driver
.type
= TTY_DRIVER_TYPE_SERIAL
;
307 rs285_driver
.subtype
= SERIAL_TYPE_NORMAL
;
308 rs285_driver
.init_termios
= tty_std_termios
;
309 rs285_driver
.init_termios
.c_cflag
= baud
| CS8
| CREAD
| HUPCL
| CLOCAL
;
310 rs285_driver
.flags
= TTY_DRIVER_REAL_RAW
;
311 rs285_driver
.refcount
= &rs285_refcount
;
312 rs285_driver
.table
= rs285_table
;
313 rs285_driver
.termios
= rs285_termios
;
314 rs285_driver
.termios_locked
= rs285_termios_locked
;
316 rs285_driver
.open
= rs285_open
;
317 rs285_driver
.close
= rs285_close
;
318 rs285_driver
.write
= rs285_write
;
319 rs285_driver
.put_char
= rs285_put_char
;
320 rs285_driver
.write_room
= rs285_write_room
;
321 rs285_driver
.chars_in_buffer
= rs285_chars_in_buffer
;
322 rs285_driver
.flush_buffer
= rs285_flush_buffer
;
323 rs285_driver
.throttle
= rs285_throttle
;
324 rs285_driver
.unthrottle
= rs285_unthrottle
;
325 rs285_driver
.send_xchar
= rs285_send_xchar
;
326 rs285_driver
.set_termios
= rs285_set_termios
;
327 rs285_driver
.stop
= rs285_stop
;
328 rs285_driver
.start
= rs285_start
;
329 rs285_driver
.wait_until_sent
= rs285_wait_until_sent
;
331 callout_driver
= rs285_driver
;
332 callout_driver
.name
= SERIAL_21285_AUXNAME
;
333 callout_driver
.major
= SERIAL_21285_AUXMAJOR
;
334 callout_driver
.subtype
= SERIAL_TYPE_CALLOUT
;
336 if (request_irq(IRQ_CONRX
, rs285_rx_int
, 0, "rs285", NULL
))
337 panic("Couldn't get rx irq for rs285");
339 if (request_irq(IRQ_CONTX
, rs285_tx_int
, 0, "rs285", NULL
))
340 panic("Couldn't get tx irq for rs285");
342 if (tty_register_driver(&rs285_driver
))
343 printk(KERN_ERR
"Couldn't register 21285 serial driver\n");
344 if (tty_register_driver(&callout_driver
))
345 printk(KERN_ERR
"Couldn't register 21285 callout driver\n");
350 static void __exit
rs285_fini(void)
357 ret
= tty_unregister_driver(&callout_driver
);
359 printk(KERN_ERR
"Unable to unregister 21285 callout driver "
361 ret
= tty_unregister_driver(&rs285_driver
);
363 printk(KERN_ERR
"Unable to unregister 21285 driver (%d)\n",
365 free_irq(IRQ_CONTX
, NULL
);
366 free_irq(IRQ_CONRX
, NULL
);
367 restore_flags(flags
);
370 module_init(rs285_init
);
371 module_exit(rs285_fini
);
373 #ifdef CONFIG_SERIAL_21285_CONSOLE
374 /************** console driver *****************/
376 static void rs285_console_write(struct console
*co
, const char *s
, u_int count
)
380 disable_irq(IRQ_CONTX
);
381 for (i
= 0; i
< count
; i
++) {
382 while (*CSR_UARTFLG
& 0x20);
385 while (*CSR_UARTFLG
& 0x20);
389 enable_irq(IRQ_CONTX
);
392 static int rs285_console_wait_key(struct console
*co
)
396 disable_irq(IRQ_CONRX
);
397 while (*CSR_UARTFLG
& 0x10);
399 enable_irq(IRQ_CONRX
);
403 static kdev_t
rs285_console_device(struct console
*c
)
405 return MKDEV(SERIAL_21285_MAJOR
, SERIAL_21285_MINOR
);
408 static int __init
rs285_console_setup(struct console
*co
, char *options
)
413 int cflag
= CREAD
| HUPCL
| CLOCAL
;
415 if (machine_is_personal_server())
420 baud
= simple_strtoul(options
, NULL
, 10);
421 while (*s
>= '0' && *s
<= '9')
430 * Now construct a cflag setting.
480 rs285_set_cflag(cflag
);
481 rs285_console_write(NULL
, "\e[2J\e[Hboot ", 12);
483 rs285_console_write(NULL
, options
, strlen(options
));
485 rs285_console_write(NULL
, "no options", 10);
486 rs285_console_write(NULL
, "\n", 1);
491 static struct console rs285_cons
=
493 name
: SERIAL_21285_NAME
,
494 write
: rs285_console_write
,
495 device
: rs285_console_device
,
496 wait_key
: rs285_console_wait_key
,
497 setup
: rs285_console_setup
,
498 flags
: CON_PRINTBUFFER
,
502 void __init
rs285_console_init(void)
504 register_console(&rs285_cons
);
507 #endif /* CONFIG_SERIAL_21285_CONSOLE */