]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/serial/atmel_usart.c
dm: at91: Refactor serial driver slightly for driver model
[karo-tx-uboot.git] / drivers / serial / atmel_usart.c
1 /*
2  * Copyright (C) 2004-2006 Atmel Corporation
3  *
4  * Modified to support C structur SoC access by
5  * Andreas Bießmann <biessmann@corscience.de>
6  *
7  * SPDX-License-Identifier:     GPL-2.0+
8  */
9 #include <common.h>
10 #include <watchdog.h>
11 #include <serial.h>
12 #include <linux/compiler.h>
13
14 #include <asm/io.h>
15 #include <asm/arch/clk.h>
16 #include <asm/arch/hardware.h>
17
18 #include "atmel_usart.h"
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 static void atmel_serial_setbrg_internal(atmel_usart3_t *usart, int id,
23                                          int baudrate)
24 {
25         unsigned long divisor;
26         unsigned long usart_hz;
27
28         /*
29          *              Master Clock
30          * Baud Rate = --------------
31          *                16 * CD
32          */
33         usart_hz = get_usart_clk_rate(id);
34         divisor = (usart_hz / 16 + baudrate / 2) / baudrate;
35         writel(USART3_BF(CD, divisor), &usart->brgr);
36 }
37
38 static void atmel_serial_init_internal(atmel_usart3_t *usart)
39 {
40         /*
41          * Just in case: drain transmitter register
42          * 1000us is enough for baudrate >= 9600
43          */
44         if (!(readl(&usart->csr) & USART3_BIT(TXEMPTY)))
45                 __udelay(1000);
46
47         writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr);
48 }
49
50 static void atmel_serial_activate(atmel_usart3_t *usart)
51 {
52         writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL)
53                            | USART3_BF(USCLKS, USART3_USCLKS_MCK)
54                            | USART3_BF(CHRL, USART3_CHRL_8)
55                            | USART3_BF(PAR, USART3_PAR_NONE)
56                            | USART3_BF(NBSTOP, USART3_NBSTOP_1)),
57                            &usart->mr);
58         writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr);
59         /* 100us is enough for the new settings to be settled */
60         __udelay(100);
61 }
62
63 static void atmel_serial_setbrg(void)
64 {
65         atmel_serial_setbrg_internal((atmel_usart3_t *)CONFIG_USART_BASE,
66                                      CONFIG_USART_ID, gd->baudrate);
67 }
68
69 static int atmel_serial_init(void)
70 {
71         atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
72
73         atmel_serial_init_internal(usart);
74         serial_setbrg();
75         atmel_serial_activate(usart);
76
77         return 0;
78 }
79
80 static void atmel_serial_putc(char c)
81 {
82         atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
83
84         if (c == '\n')
85                 serial_putc('\r');
86
87         while (!(readl(&usart->csr) & USART3_BIT(TXRDY)));
88         writel(c, &usart->thr);
89 }
90
91 static int atmel_serial_getc(void)
92 {
93         atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
94
95         while (!(readl(&usart->csr) & USART3_BIT(RXRDY)))
96                  WATCHDOG_RESET();
97         return readl(&usart->rhr);
98 }
99
100 static int atmel_serial_tstc(void)
101 {
102         atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE;
103         return (readl(&usart->csr) & USART3_BIT(RXRDY)) != 0;
104 }
105
106 static struct serial_device atmel_serial_drv = {
107         .name   = "atmel_serial",
108         .start  = atmel_serial_init,
109         .stop   = NULL,
110         .setbrg = atmel_serial_setbrg,
111         .putc   = atmel_serial_putc,
112         .puts   = default_serial_puts,
113         .getc   = atmel_serial_getc,
114         .tstc   = atmel_serial_tstc,
115 };
116
117 void atmel_serial_initialize(void)
118 {
119         serial_register(&atmel_serial_drv);
120 }
121
122 __weak struct serial_device *default_serial_console(void)
123 {
124         return &atmel_serial_drv;
125 }