1 // SPDX-License-Identifier: GPL-2.0
3 * Serial port driver for BCM2835AUX UART
5 * Copyright (C) 2016 Martin Sperl <kernel@martin.sperl.org>
7 * Based on 8250_lpc18xx.c:
8 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
10 * The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't
11 * take advantage of it yet. When adding support, be sure not to enable it
12 * simultaneously to rs485.
15 #include <linux/clk.h>
17 #include <linux/module.h>
19 #include <linux/platform_device.h>
23 #define BCM2835_AUX_UART_CNTL 8
24 #define BCM2835_AUX_UART_CNTL_RXEN 0x01 /* Receiver enable */
25 #define BCM2835_AUX_UART_CNTL_TXEN 0x02 /* Transmitter enable */
26 #define BCM2835_AUX_UART_CNTL_AUTORTS 0x04 /* RTS set by RX fill level */
27 #define BCM2835_AUX_UART_CNTL_AUTOCTS 0x08 /* CTS stops transmitter */
28 #define BCM2835_AUX_UART_CNTL_RTS3 0x00 /* RTS set until 3 chars left */
29 #define BCM2835_AUX_UART_CNTL_RTS2 0x10 /* RTS set until 2 chars left */
30 #define BCM2835_AUX_UART_CNTL_RTS1 0x20 /* RTS set until 1 chars left */
31 #define BCM2835_AUX_UART_CNTL_RTS4 0x30 /* RTS set until 4 chars left */
32 #define BCM2835_AUX_UART_CNTL_RTSINV 0x40 /* Invert auto RTS polarity */
33 #define BCM2835_AUX_UART_CNTL_CTSINV 0x80 /* Invert auto CTS polarity */
36 * struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
37 * @clk: clock producer of the port's uartclk
38 * @line: index of the port's serial8250_ports[] entry
39 * @cntl: cached copy of CNTL register
41 struct bcm2835aux_data
{
47 static void bcm2835aux_rs485_start_tx(struct uart_8250_port
*up
)
49 if (!(up
->port
.rs485
.flags
& SER_RS485_RX_DURING_TX
)) {
50 struct bcm2835aux_data
*data
= dev_get_drvdata(up
->port
.dev
);
52 data
->cntl
&= ~BCM2835_AUX_UART_CNTL_RXEN
;
53 serial_out(up
, BCM2835_AUX_UART_CNTL
, data
->cntl
);
57 * On the bcm2835aux, the MCR register contains no other
58 * flags besides RTS. So no need for a read-modify-write.
60 if (up
->port
.rs485
.flags
& SER_RS485_RTS_ON_SEND
)
61 serial8250_out_MCR(up
, 0);
63 serial8250_out_MCR(up
, UART_MCR_RTS
);
66 static void bcm2835aux_rs485_stop_tx(struct uart_8250_port
*up
)
68 if (up
->port
.rs485
.flags
& SER_RS485_RTS_AFTER_SEND
)
69 serial8250_out_MCR(up
, 0);
71 serial8250_out_MCR(up
, UART_MCR_RTS
);
73 if (!(up
->port
.rs485
.flags
& SER_RS485_RX_DURING_TX
)) {
74 struct bcm2835aux_data
*data
= dev_get_drvdata(up
->port
.dev
);
76 data
->cntl
|= BCM2835_AUX_UART_CNTL_RXEN
;
77 serial_out(up
, BCM2835_AUX_UART_CNTL
, data
->cntl
);
81 static int bcm2835aux_serial_probe(struct platform_device
*pdev
)
83 struct uart_8250_port up
= { };
84 struct bcm2835aux_data
*data
;
88 /* allocate the custom structure */
89 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
94 up
.capabilities
= UART_CAP_FIFO
| UART_CAP_MINI
;
95 up
.port
.dev
= &pdev
->dev
;
97 up
.port
.type
= PORT_16550
;
98 up
.port
.iotype
= UPIO_MEM
;
100 up
.port
.flags
= UPF_SHARE_IRQ
| UPF_FIXED_PORT
| UPF_FIXED_TYPE
|
101 UPF_SKIP_TEST
| UPF_IOREMAP
;
102 up
.port
.rs485_config
= serial8250_em485_config
;
103 up
.rs485_start_tx
= bcm2835aux_rs485_start_tx
;
104 up
.rs485_stop_tx
= bcm2835aux_rs485_stop_tx
;
106 /* initialize cached copy with power-on reset value */
107 data
->cntl
= BCM2835_AUX_UART_CNTL_RXEN
| BCM2835_AUX_UART_CNTL_TXEN
;
109 platform_set_drvdata(pdev
, data
);
111 /* get the clock - this also enables the HW */
112 data
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
113 if (IS_ERR(data
->clk
))
114 return dev_err_probe(&pdev
->dev
, PTR_ERR(data
->clk
), "could not get clk\n");
116 /* get the interrupt */
117 ret
= platform_get_irq(pdev
, 0);
122 /* map the main registers */
123 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
125 dev_err(&pdev
->dev
, "memory resource not found");
128 up
.port
.mapbase
= res
->start
;
129 up
.port
.mapsize
= resource_size(res
);
131 /* Check for a fixed line number */
132 ret
= of_alias_get_id(pdev
->dev
.of_node
, "serial");
136 /* enable the clock as a last step */
137 ret
= clk_prepare_enable(data
->clk
);
139 dev_err(&pdev
->dev
, "unable to enable uart clock - %d\n",
144 /* the HW-clock divider for bcm2835aux is 8,
145 * but 8250 expects a divider of 16,
146 * so we have to multiply the actual clock by 2
147 * to get identical baudrates.
149 up
.port
.uartclk
= clk_get_rate(data
->clk
) * 2;
151 /* register the port */
152 ret
= serial8250_register_8250_port(&up
);
154 dev_err_probe(&pdev
->dev
, ret
, "unable to register 8250 port\n");
162 clk_disable_unprepare(data
->clk
);
166 static int bcm2835aux_serial_remove(struct platform_device
*pdev
)
168 struct bcm2835aux_data
*data
= platform_get_drvdata(pdev
);
170 serial8250_unregister_port(data
->line
);
171 clk_disable_unprepare(data
->clk
);
176 static const struct of_device_id bcm2835aux_serial_match
[] = {
177 { .compatible
= "brcm,bcm2835-aux-uart" },
180 MODULE_DEVICE_TABLE(of
, bcm2835aux_serial_match
);
182 static struct platform_driver bcm2835aux_serial_driver
= {
184 .name
= "bcm2835-aux-uart",
185 .of_match_table
= bcm2835aux_serial_match
,
187 .probe
= bcm2835aux_serial_probe
,
188 .remove
= bcm2835aux_serial_remove
,
190 module_platform_driver(bcm2835aux_serial_driver
);
192 #ifdef CONFIG_SERIAL_8250_CONSOLE
194 static int __init
early_bcm2835aux_setup(struct earlycon_device
*device
,
197 if (!device
->port
.membase
)
200 device
->port
.iotype
= UPIO_MEM32
;
201 device
->port
.regshift
= 2;
203 return early_serial8250_setup(device
, NULL
);
206 OF_EARLYCON_DECLARE(bcm2835aux
, "brcm,bcm2835-aux-uart",
207 early_bcm2835aux_setup
);
210 MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
211 MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
212 MODULE_LICENSE("GPL v2");